odoo-mcp provides 18 tools with generally present descriptions and schemas, but exhibits significant quality gaps. Tool naming is verb-driven and mostly clear (search_, read_, create_, update_, delete_, execute_), following the pattern:tool convention well. However, parameter descriptions are inconsistent in detail and precision. Many parameters lack concrete constraints (enums, min/max ranges), forcing LLMs to guess valid formats. Domain strings exemplify this: tools accept domain filters as JSON array strings (e.g., '[["is_company","=",true]]'), but the parameter descriptions are vague about syntax and don't explicitly state that malformed JSON will fail. Output schemas are largely undocumented, tools return results but the structure of returned objects is not formally specified in the schema definitions. Error handling exists (try/catch in handlers) but recovery guidance is minimal. The server handles credentials properly (environment variables, no token params), which is good. Overall, the server is functional for basic Odoo integration but lacks the polish and explicit constraints expected of production-grade agent tools.
Tools (18)
count_recordsread onlyauthsource verified73/100
Count records in an Odoo model matching an optional domain filter.
create_recordwriteauthsource verified73/100
Create one or more records in an Odoo model. Supports both single and batch creation.
delete_recorddestructiveauthsource verified73/100
Delete one or more records from an Odoo model. Use with caution — this is permanent.
Download/read an attachment by ID. Returns the base64-encoded file content.
execute_methodwriteauthsource verified75/100
Execute a method on Odoo model records. Used for workflow actions (action_confirm, action_post, button_validate, etc.) and custom business logic methods. Note: create/write/unlink are blocked — use dedicated tools instead.
get_fieldsread onlyauthsource verified72/100
Get field definitions for an Odoo model. Returns field names, types, labels, and other metadata. Default: returns string, type, required, readonly, relation only (compact mode).
Domain parameter format not rigorously specified. Tools like search_records, count_records, and search_grouped accept 'domain' as a JSON array string (e.g., '[["is_company","=",true]]'), but parameter descriptions lack explicit syntax rules, valid JSON requirements, or malformed input handling guidance. LLMs may pass invalid domain strings, causing silent failures or unclear error messages.
Output schemas undocumented. Tools define input schemas but responses are returned as opaque JSON without documented field structure. For example, search_records returns records with id, name, display_name and optional custom fields, but the response schema is never formally declared. This forces LLMs to infer field names and types from examples or trial-and-error.
Add explicit JSON schema validation to domain parameters. Document valid domain syntax with examples: '["field_name", "operator", value]' where operator is one of '=', '!=', '>', '<', '>=', '<=', 'ilike', 'like', 'in', 'not in'. Provide sample domains for common queries (is_company=true, create_date >= 2024-01-01).
Document output schemas formally in each tool definition. For search_records, specify: returns {records: [{id: number, name: string, display_name: string, ...custom_fields}], total_count?: number}. Use JSON Schema format or explicit field descriptions.
Enhance error messages with recovery hints. When domain parsing fails, return: 'Invalid domain syntax. Expected JSON array of [field, operator, value] tuples. Example: [["state", "=", "draft"], ["amount", ">", 100]]. Call list_models() to explore available fields.' Categorize errors as retryable vs. unrecoverable.
Document special parameter syntax for search_grouped. Explain 'fields' format: 'field_name' for grouping, 'field_name:agg' for aggregation (valid aggs: sum, count, avg, min, max, count_distinct). Example: 'amount_total:sum,quantity:count'. Document 'groupby' format: 'field_name' or 'field_name:period' where period is month, year, week, day, quarter for date fields.
Score history
Overall score trend
↑ 44 points across a rubric change (v1 → v2)
57/100
Scored
Grade
Overall
Spec posture
Rubric
2026-09-22
D
57
2026-07-28+
v2
2026-03-09
F
13
-
v1
get_messagesread onlyauthsource verified75/100
Get chatter messages and change history for a specific record. Returns comments, internal notes, and tracking changes.
List file attachments on a specific Odoo record or search all attachments.
list_modelsread onlyauthsource verified75/100
List available Odoo models. By default excludes transient (wizard) models. Use filter to narrow results.
name_searchread onlyauthsource verified75/100
Search records by name with autocomplete-style matching. Returns [id, display_name] pairs. Useful for finding records by partial name before creating relational links.
post_messagewriteauthsource verified73/100
Post a message or internal note on an Odoo record's chatter. Uses the message_post method.
read_recordread onlyauthsource verified77/100
Read one or more records by their IDs from an Odoo model.
search_calendarread onlyauthsource verified65/100
캘린더 일정을 조회합니다. 기본적으로 현재 인증된 사용자 본인의 일정 및 본인이 참석자로 포함된 일정만 반환합니다. all_events를 true로 설정하면 전체 일정을 조회할 수 있습니다.
search_groupedread onlyauthsource verified67/100
Search and aggregate records using Odoo's read_group. Returns grouped results with aggregated values (sum, count, avg, etc.).
search_recordsread onlyauthsource verified75/100
Search and read records from an Odoo model. If fields is not specified, only id/name/display_name are returned to keep response compact. Always specify the fields you need.
update_recordwriteauthsource verified73/100
Update one or more existing records in an Odoo model.
upload_attachmentwriteauthsource verified73/100
Upload a file attachment to an Odoo record. File content must be base64-encoded.
whoamiread onlyauthsource verified73/100
Show current connection info: authenticated user, uid, partner, company, server version, and database name.
Numeric parameter constraints missing. Parameters like 'limit', 'offset', 'port' lack min/max specifications. search_records has limit defaulting to 80 with no stated maximum; LLMs could request 10,000 records, risking timeouts or memory exhaustion. No explicit range validation documented.
Error recovery guidance absent. Tools return generic error messages (see src/index.ts line 56: JSON.stringify({ error: message })) without actionable next steps. When domain syntax is invalid, LLM receives 'error: invalid domain' but no hint to check JSON format or call list_models() first for exploration.
Parameter relationships undocumented. search_grouped accepts 'fields' with ':agg' suffix (e.g., 'amount_total:sum') and 'groupby' with ':month' suffix (e.g., 'date_order:month'), but parameter descriptions do not explain this special syntax or valid aggregation types (sum, count, avg, min, max). LLMs must guess valid formats.
Mutually exclusive parameters not declared. execute_method accepts both 'args' (positional arguments as JSON array) and 'kwargs' (keyword arguments as JSON object), but no guidance on which to use or how they compose. LLMs may pass both when only one is valid for the target method.
Destructive operations lack confirmation pattern. delete_record is permanently destructive but provides no dry-run or confirmation step. An agent mistakenly calling delete_record with wrong IDs results in data loss with no recovery option. No mention of backup or reversibility in description.
Batch operation error semantics unclear. create_record and update_record support batch operations (multiple records in one call) but do not specify per-item failure handling. If one record fails in a batch of 10, does the entire call fail, or are partial results returned with per-item status? Documentation lacks clarity.
Description uses localized text mixed with English. search_grouped includes 'lazy' parameter description mentioning 'sub-groups returned via __context', but get_fields uses Korean text ('true로 설정하면 모든 속성을 반환합니다'). Mixed-language descriptions reduce clarity and may confuse LLMs trained primarily on English.
get_fieldssearch_calendar
Clarify mutual exclusivity in execute_method. Specify: 'args and kwargs are combined; args are positional, kwargs are keyword. Most methods accept either but not both. Check the method signature before calling. Example: method action_confirm typically takes no arguments (args=[], kwargs={}).'
Add dry-run support to delete_record. Offer a 'dry_run' boolean parameter: 'If true, validate IDs exist but do not delete. Useful to confirm targets before permanent removal.' Return matching record IDs without deletion.
Document batch operation error handling. Specify: 'If creating/updating multiple records, returns {succeeded: [id1, id2, ...], failed: [{id, error}]}. If any record fails, partial results are returned; transaction is not atomic. For atomic semantics, call the tool once per record.'
Standardize parameter descriptions to English. Translate Korean descriptions (get_fields all_attributes, search_calendar all_events, search_calendar fields, search_calendar limit, search_calendar order, search_calendar domain) to English for consistency and LLM clarity.
Add dependency hints to discovery tools. list_models description should state: 'Call this first to explore available models before search_records() or create_record(). Use filter to narrow results by domain (e.g., filter="sale" returns sale.order, sale.order.line, etc.).' get_fields should say: 'Call after list_models() to understand field types and constraints before constructing domain filters or create/update payloads.'
Document required vs. optional fields for create_record and update_record. Provide: 'Call get_fields(model) to see field metadata. required=true fields must be provided in create_record. Many fields have defaults set in Odoo (e.g., state=draft, create_date=now). Check field definition to understand behavior.' Include example create payloads.
Add rate limiting and timeout guidance. Specify in tool descriptions: 'Requests timeout after 30 seconds (configurable via ODOO_TIMEOUT env var). If large search_records calls time out, reduce limit or add more specific domain filters. Odoo may rate-limit high request volumes; retry with exponential backoff.'
Separate search_grouped lazy mode documentation. 'lazy=true (default) groups by first field only; result structure differs from lazy=false. Use lazy=false for multi-level grouping, but expect larger response. Document the __context and __domain fields returned in lazy mode.'
Add idempotency guidance. Specify which tools are safe to retry: 'search_records, read_record, get_fields, list_models, count_records are read-only and safe. create_record, update_record, delete_record, post_message, upload_attachment are not idempotent; repeating with the same args may create duplicates or overwrite unintended data. Use dry_run or conditional logic to avoid repeats.'
Document name_search operator enum with descriptions. Currently: operator enum=['ilike','like','=','not ilike','not like','=like','=ilike']. Add hints: 'ilike = case-insensitive substring (default), like = case-sensitive substring, = = exact match. Most Odoo searches use ilike for flexibility.'
Explain attachment upload limitations. upload_attachment accepts base64 content but lacks stated file size limits. Document: 'File size must not exceed Odoo server limit (typically 25 - 100 MB; check Odoo configuration). base64 encoding inflates size by ~33%. Pre-check file size before encoding to avoid wasted computation.'
Add context about Odoo versioning. whoami returns 'server version' but tools may have version-dependent behavior (e.g., grouped aggregations differ in Odoo 13 vs. 16). Document: 'Many Odoo features are version-dependent. Call whoami() first to confirm server version. If operations fail, check server version compatibility in Odoo documentation.'
Provide examples of method calls in execute_method. Specify common workflow methods: 'action_confirm (sale.order), action_post (account.move), button_validate (stock.picking). Most take no args/kwargs. Custom methods may require domain-specific arguments; check Odoo module documentation.' Include failure modes (e.g., 'state must be draft to confirm').