Skip to content

v0.7.0

Choose a tag to compare

@ivnvxd ivnvxd released this 11 Jun 13:38
Immutable release. Only release title and notes can be modified.
1d4ebb5

Fixed

  • delete_record on records without a display name (e.g. mail.message): the unlink succeeded but the result then failed schema validation (deleted_name received Odoo's False), so clients believed the delete had failed — now falls back to an ID label.
  • Timeouts: Socket timeouts now actually apply to XML-RPC connections — a hung Odoo server fails fast instead of blocking forever.
  • Half-open keepalive recovery (#68): a timeout on a reused keepalive socket (LB dropped the upstream without FIN/RST) transparently retries once on a fresh connection — idempotent calls only: read-only model methods plus login/version/db-list probes (a timed-out write is never re-sent, it could be double-executed by a slow server); timeouts on fresh connections are NOT retried.
  • streamable-http sessions (#70): the Odoo connection and registered handlers now persist across HTTP sessions — previously every tool call after the first failed with "Not authenticated with Odoo" because session teardown disconnected Odoo. stdio still cleans up on exit.
  • Event loop: Blocking XML-RPC/HTTP calls offloaded to worker threads; concurrent tool calls and pings stay responsive during slow operations.
  • YOLO list_models: System-model exclusion was a no-op (tautological domain) — results were dominated by ir.*/base.* models.
  • Domain parsing: String domains no longer corrupt values containing True/False substrings (e.g. 'True North').
  • Binary fields: search_records/get_record results with binary/datetime fields serialize cleanly instead of erroring.
  • fields=[]: Treated as smart defaults instead of silently fetching ALL fields.
  • list_resource_templates: YOLO mode reports "all models available" instead of total_models: 0.
  • Search resource: odoo://{model}/search skips binary/html fields like the record path; pagination hints now reference the search_records tool instead of emitting unroutable query-param URIs.
  • Formatters: Float precision honors digits metadata; unset names render Record {id} instead of False; long values truncated with a marker; x2many "View all" hints carry real record ids.
  • Cache: Memory budget actually enforced (looped eviction); replacing a key no longer evicts an unrelated entry.
  • Error sanitizer: Server tracebacks reduced to the final error message (multi-line business errors kept intact) — no more leaked source lines, SQL constraint names, or row values; no more literal {} placeholders in error messages.
  • Error classification: Builtin PermissionError/ConnectionError no longer misclassified as critical system errors (custom classes shadowed the builtins); access-control infrastructure failures report as connection errors, not "Access denied".
  • Config precedence: ODOO_MCP_TRANSPORT/HOST/PORT/LOG_LEVEL set only in .env now take effect; invalid ODOO_MCP_PORT or ODOO_MCP_SLOW_OPERATION_THRESHOLD_MS no longer crash startup/import with raw tracebacks.
  • Auth fallback: After a rejected API key falls back to password auth, permission checks use session auth instead of resending the dead key (which 401'd every tool call).
  • Logging: Sensitive keys (passwords, API keys, tokens) redacted in debug-log write payloads; database names moved to DEBUG level.
  • Version: SERVER_VERSION derives from the package version; a test pins it to pyproject.toml (v0.5.2 shipped reporting 0.5.1).

Changed

  • TLS: HTTPS transports share one ssl.SSLContext to amortize handshake cost across the per-proxy sockets introduced in 0.6.0.
  • HTTP transport: Loud startup warning when binding a non-loopback host (the transport has no built-in authentication); README security notes added.
  • Dead code removed (~550 lines): never-wired record/permission caches, RequestOptimizer, the browse resource chain, and the unused error metrics/conversion API; ConnectionPool simplified to the proxy factory it actually was.
  • CI: Push trigger limited to main/dev (PRs cover feature branches; kills duplicate runs); Dependabot switched to the uv ecosystem so uv.lock gets update/security PRs; publish workflow verifies the built version against the release tag (manual dispatch requires typed version confirmation); Python 3.13 classifier added; MCP integration job skips Dependabot PRs — repository secrets aren't available to them, so the private-module checkout failed with "Input required and not supplied: token"; Dependabot version-update PRs now target dev directly (manual retargeting desynced Dependabot's base-branch metadata); codecov-action bumped to v7 (supersedes the stuck Dependabot PR).
  • --help: documents ODOO_MCP_ENABLE_METHOD_CALLS.
  • Tests: integration suite hardened — MCP-module detection works on multi-database instances (health probe sends X-Odoo-Database); an env-var leak that wedged spawned transport servers under DEBUG logging fixed; vacuous if records: guards replaced with real fixtures and assertions; MCP test client read_resource returned "" (matched the wrong content type).