preview_write
Preview create, write, or unlink operations on Odoo models without committing changes to the database.
Instructions
Preview create, write, or unlink without executing it
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| model | Yes | ||
| operation | Yes | ||
| values | No | ||
| record_ids | No | ||
| context | No |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
| result | Yes |
Implementation Reference
- src/odoo_mcp/server.py:1403-1427 (handler)MCP tool handler for 'preview_write' — registered via @mcp.tool decorator with PREVIEW_TOOL annotations. Validates model name, then delegates to build_write_preview_report().
@mcp.tool( description="Preview create, write, or unlink without executing it", annotations=PREVIEW_TOOL, structured_output=True, ) def preview_write( model: str, operation: str, values: Optional[Dict[str, Any]] = None, record_ids: Optional[List[int]] = None, context: Optional[Dict[str, Any]] = None, ) -> Dict[str, Any]: """Build a canonical approval token for a later approved write.""" try: validate_model_name(model) return build_write_preview_report( model=model, operation=operation, values=values, record_ids=record_ids, context=context, ) except Exception as e: return {"success": False, "tool": "preview_write", "error": str(e)} - src/odoo_mcp/agent_tools.py:84-158 (helper)build_write_preview_report() — the core logic that builds the non-executing preview for create/write/unlink. Normalizes operation, validates inputs, builds a canonical payload with an approval token, and returns the response with tool='preview_write'.
def build_write_preview_report( *, model: str, operation: str, values: dict[str, Any] | None = None, record_ids: list[int] | None = None, context: dict[str, Any] | None = None, ) -> dict[str, Any]: """Build a non-executing preview for standard ORM write operations.""" normalized_operation = operation.strip().lower() issues: list[dict[str, str]] = [] if normalized_operation not in WRITE_OPERATIONS: issues.append( { "code": "unsupported_write_operation", "severity": "error", "message": "operation must be one of create, write, or unlink.", } ) normalized_values = dict(values or {}) normalized_ids = [int(record_id) for record_id in record_ids or []] if normalized_operation == "create" and not normalized_values: issues.append( { "code": "missing_create_values", "severity": "error", "message": "create requires non-empty values.", } ) if normalized_operation in {"write", "unlink"} and not normalized_ids: issues.append( { "code": "missing_record_ids", "severity": "error", "message": f"{normalized_operation} requires record_ids.", } ) if normalized_operation == "write" and not normalized_values: issues.append( { "code": "missing_write_values", "severity": "error", "message": "write requires non-empty values.", } ) canonical_payload = { "model": model, "operation": normalized_operation, "record_ids": normalized_ids, "values": normalized_values, "context": dict(context or {}), } approval_token = build_approval_token(canonical_payload) return { "success": not any(issue["severity"] == "error" for issue in issues), "tool": "preview_write", "model": model, "operation": normalized_operation, "approval": {**canonical_payload, "token": approval_token}, "execute_method": _write_execute_method_args(canonical_payload), "issues": issues, "warnings": [ { "code": "destructive_operation", "message": ( "This preview does not execute. execute_approved_write is " "destructive and requires the matching approval token plus confirm=true." ), } ], "metadata_used": {"client_instantiated": False}, } - src/odoo_mcp/agent_tools.py:265-282 (helper)_write_execute_method_args() — helper that constructs the model/method/args/kwargs dict for a canonical write payload, used by build_write_preview_report to return the 'execute_method' field.
def _write_execute_method_args(payload: dict[str, Any]) -> dict[str, Any]: operation = str(payload["operation"]) context = payload.get("context") or {} kwargs = {"context": context} if context else {} if operation == "create": args: list[Any] = [payload.get("values") or {}] elif operation == "write": args = [payload.get("record_ids") or [], payload.get("values") or {}] elif operation == "unlink": args = [payload.get("record_ids") or []] else: args = [] return { "model": payload.get("model"), "method": operation, "args": args, "kwargs": kwargs, } - src/odoo_mcp/agent_tools.py:78-81 (helper)build_approval_token() — helper that builds a deterministic SHA-256 approval token from the canonical payload, used by build_write_preview_report.
def build_approval_token(payload: dict[str, Any]) -> str: """Build a deterministic approval token for a canonical write preview.""" digest = hashlib.sha256(canonical_json(payload).encode("utf-8")).hexdigest() return f"odoo-write:{digest[:32]}" - src/odoo_mcp/server.py:88-90 (registration)PREVIEW_TOOL annotation used in the @mcp.tool registration for preview_write (readOnlyHint=True, destructiveHint=False, idempotentHint=True, openWorldHint=False).
PREVIEW_TOOL = ToolAnnotations( readOnlyHint=True, destructiveHint=False, idempotentHint=True, openWorldHint=False )