Skip to content

refactor(odoo)!: registerTool, Odoo 19 fixes and leaner tool surface - #31

Merged
unclecatvn merged 1 commit into
masterfrom
refactor/odoo-review
Oct 15, 2026
Merged

unclecatvn merged 1 commit into
masterfrom
refactor/odoo-review

Conversation

@unclecatvn

Copy link
Copy Markdown
Owner

Why

A review of the Odoo server found two real bugs and a tool surface that was larger than it needed to be:

  • name_search with a domain failed on every Odoo 19 instance: ResCountry.name_search() got an unexpected keyword argument 'args'. Odoo 18 names that parameter args; Odoo 19 renamed it to domain.
  • The request timeout was cleared as soon as headers arrived, so a response whose body stalled hung forever.
  • Tool JSON Schemas were hand-written next to identical zod schemas (two sources of truth). The instructions were about 7 KB, but Claude Code truncates server instructions at about 2 KB, so the error-code section never reached the model.

This is the planned 1.0.0 change for @unclecat/mcp-odoo (major changeset included).

What changes

Area Before After
name_search args sent as a kwarg (breaks on 19) name and domain sent positionally (works on 18 and 19)
Timeout setTimeout, cleared after headers AbortSignal.timeout, which also bounds the body read
Tool registration low-level Server + hand-written JSON Schema + zod + switch dispatch McpServer.registerTool with strict zod schemas only
Errors 10 near-identical classes; details / retryable never reached the client one OdooError(code, message) whose message carries [CODE]
search_read unlimited by default limit defaults to 100; returns limit_reached: true on a full page
Annotations none readOnlyHint on reads, destructiveHint on write / unlink / call_method
Prompt cost ~5.8k tokens per session ~3.3k tokens; instructions are 1,494 chars
Dead code validators.js, clientRegistry.js, index.d.ts (declared exports index.js never had), clearFieldsCache, shutdown handlers removed

Net: 19 files, +650 / −2,090 lines.

Breaking changes

  • ODOO_INPUT_INVALID is gone. Invalid arguments, including unknown keys, now return the SDK's Input validation error: ... text.
  • search_read without a limit returns at most 100 records.
  • Client-side regex checks on connection, model and method names were dropped; Odoo already rejects bad names with a clear error.

Verification

  • pnpm -r test: odoo 50, obsidian 41, db 203 passing. Odoo coverage is 98.9%. Lint and format are clean, and pnpm install --frozen-lockfile passes.
  • New tests cover the Odoo 19 name_search payload, a stalled-body timeout, the default limit, annotations, strict-key rejection and the under-2 KB instructions size.
  • Ran read-only calls against a live Odoo 19.0.1.3 instance with MCP SDK 1.31: name_search with a domain now returns [[241, "Vietnam"]]; search_read returns 100 rows with limit_reached: true; read_group works; an unknown key is rejected.

Follow-ups

  • The JSON-2 transport for Odoo 19+ (/jsonrpc is deprecated in 19 and removed in 22) lives on feat/odoo-json2-transport and will rebase onto this branch.
  • For the 1.0.0 release: major changesets for db and obsidian, and switch the README install commands to @1.

Fixes:
- name_search with a domain failed on Odoo 19 ("unexpected keyword
  argument 'args'"): name and domain are now sent positionally, which
  works on 18 (`args`) and 19 (`domain`).
- The request timeout was cleared once headers arrived, so a stalled
  body hung forever. AbortSignal.timeout now bounds the body read too.

Changes:
- Move to McpServer.registerTool with strict zod schemas as the single
  source of truth; drop the hand-written JSON Schemas, parseOrThrow and
  the dispatch switch.
- Collapse the error hierarchy into one OdooError whose message carries
  the [CODE] prefix.
- search_read defaults to limit 100 and returns limit_reached: true on a
  full page.
- Add readOnlyHint / destructiveHint tool annotations.
- Trim descriptions and instructions (~5.8k -> ~3.3k tokens per session);
  instructions now fit under the ~2 KB hosts truncate at.
- Remove dead code: validators.js, clientRegistry.js, index.d.ts,
  clearFieldsCache, shutdown handlers.
- Require zod ^3.25 (MCP SDK 1.29 peer range).

BREAKING CHANGE: ODOO_INPUT_INVALID is gone; invalid arguments now
return the SDK's "Input validation error: ..." text. search_read without
a limit now returns at most 100 records.
@unclecatvn
unclecatvn merged commit 5e26e18 into master Oct 15, 2026
9 checks passed
@unclecatvn
unclecatvn deleted the refactor/odoo-review branch October 16, 2026 02:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant