Skip to main content
Glama
singleflo

io.github.singleflo/odoo-assistant

by singleflo

Odoo Assistant MCP Server

An Odoo virtual employee via the Model Context Protocol (MCP). This server exposes Odoo's business logic, records, and workflows to LLMs, allowing them to query, create, update, and act on Odoo data safely.

Quickstart

Install with your AI agent. If you already have an AI coding assistant — Claude Code, Claude Desktop, Cursor, opencode, any of the hosts below — paste this link into your agent and ask it to set up Odoo Assistant: https://raw.githubusercontent.com/singleflo/odoo-assistant-mcp/main/docs/INSTALL-WITH-YOUR-AGENT.md That page is written for the agent rather than for you: it asks you for the Odoo URL and an API key, installs uv, writes the configuration file its own host reads, and verifies the connection. The manual route is below.

1. Install

Run the server directly:

uvx odoo-assistant

Or install it into your environment:

uv pip install odoo-assistant

Installing from source for development remains possible:

uv pip install git+https://github.com/singleflo/odoo-assistant-mcp

2. Configure Environment Variables

Don't have an API key yet?

How to create an Odoo API key → — seven steps, with a screenshot of each.

In short: avatar → Preferences → Account Security → New API Key. It is never your account password, it belongs to one Odoo user and carries exactly that user's permissions, and Odoo shows its value exactly once.

  • ODOO_BASE_URL: Mandatory always. The base URL of your Odoo instance, with no trailing slash (e.g., https://mycompany.odoo.com).

  • ODOO_API_KEY: Mandatory always. The Odoo API key (Odoo 14+ — see the box above, or docs/api-key.md). An account password is not accepted. A key is per-user, scoped, and revocable on its own. Odoo 19 additionally requires a description and an expiry, max 3 months.

  • ODOO_DB: Mandatory on Odoo Online (SaaS, *.odoo.com), optional elsewhere. On Odoo Online, the database-list endpoint is disabled. Discovery cannot find the name, and every tool call fails with an opaque "Error executing tool" without hinting that the database is the problem. With ODOO_DB set, the same config connects immediately. The SaaS database name is not the pretty subdomain — it carries a suffix, in the shape mycompany16-prod-12345678 — and you find it at /web/database/selector or in the Odoo.com account page. Elsewhere, it is discovered automatically when the instance serves exactly one database, and is required when it serves several.

  • ODOO_USER: Never mandatory. Omitted, the client probes res.users for uid 1 to 59 and keeps the one the key answers for. This adds up to 59 extra round trips on the first call, and it fails outright if the key owner's uid is 60 or higher. Setting it removes that cost. It must be the login (e.g. jane@mycompany.com), and a wrong value makes Odoo's authenticate() return False rather than raise — which reads like a permission error.

  • ODOO_MCP_ALLOW: Optional, default * — every method the deny list does not refuse. The single value none makes the server read-only, which is what you want when pointing an agent at live company data for reading. Anything else is a comma-separated list of method names. See "What the agent may do" below.

  • ODOO_MCP_DENY: Optional. Unset, it is the default deny list — unlink, archive, action_cancel, button_cancel, action_reverse, action_draft, mailing.mailing:action_send. A value you set replaces that list entirely. See "What the agent may do" below.

  • ODOO_MCP_ALLOW_UNLINK: Optional, off by default. yes, true or 1 (any case) grants unlink; no entry on either list can. See "What the agent may do" below.

  • ODOO_MCP_DATA_DIR: Optional. Where this server keeps everything it writes, the instance profiles included. It defaults to the platform's own data directory — %LOCALAPPDATA%\odoo-assistant on Windows, ~/Library/Application Support/odoo-assistant on macOS, and $XDG_DATA_HOME/odoo-assistant (else ~/.local/share/odoo-assistant) elsewhere.

Related MCP server: mcp-server-odoo

What the agent may do

Every write and every action passes a gate before it reaches Odoo. The gate judges a call by its METHOD NAME against two lists you own, in the host configuration file, and reads both from the process environment at call time:

  • ODOO_MCP_ALLOW — what may run. Unset or empty means *: every method the deny list does not refuse. The single value none makes the server read-only.

  • ODOO_MCP_DENY — what may not. Unset or empty means the default list: unlink, archive, action_cancel, button_cancel, action_reverse, action_draft, mailing.mailing:action_send. A value you set replaces that list entirely rather than extending it, so the refusals in force are exactly the names in your own file — ODOO_MCP_DENY=unlink is how you re-admit action_cancel.

An entry is either method, which matches that method on every model, or model:method, which matches it on one. Matching is exact string equality — no prefix, no substring, so action_send never matches action_send_and_print and action_cancel never matches button_cancel. A human read and approved those exact names, and a looser match would let lookalikes through that nobody saw. Deny is checked before allow, so a name on both lists refuses.

Model qualification is what the measured case needs. On one live instance 31 models answer to action_send, and only the Evolution wizards should — the one on mailing.mailing can email an entire customer base in a single call. That is why the default deny list spells that entry mailing.mailing:action_send and leaves action_send working everywhere else.

Four rules sit outside the lists:

  • unlink is decided before both of them. No value of ODOO_MCP_ALLOW or ODOO_MCP_DENY can ever grant deletion; only ODOO_MCP_ALLOW_UNLINK does — yes, true or 1, any case. Deletion is the one action that cannot be undone, and a name in a comma-separated list must never be enough to grant it.

  • archive is a virtual name. Both action_archive and a write carrying active: False carry it into the lists, so denying archive refuses hiding records however they are spelled.

  • Private methods are always refused, whatever the lists say. Odoo itself rejects every method starting with _, so no list could deliver one.

  • Reads never pass through either list, because a read has no effect for a list to govern. The account.move structural guard is untouched by any of this and still applies to them: a query mixing invoices, bills and journal entries is refused whatever the lists hold, because a meaningless read is its own hazard.

Configuration

What it permits

ODOO_MCP_ALLOW=none

Reads only. Nothing this server does can change a record — the setting for an agent pointed at live production data.

Nothing set

Default. Every method except the seven on the default deny list: creating, writing, confirming orders, posting invoices, scheduling activities, messaging users.

ODOO_MCP_ALLOW_UNLINK=yes

The default, plus unlink. The deny list is unchanged, so archive and action_cancel stay refused until you set ODOO_MCP_DENY yourself.

The lists are set out of band, by a human, and the model running against this server cannot change them. When the gate refuses, the reason names the call, the entry that decided it and the variable that would change the answer, so the agent can explain what the operation would have changed and leave the decision to you.

Note that this is the authority of this server, not of the account. An agent with shell access can always bypass an MCP server by invoking Odoo directly. A limit that must hold regardless of the client belongs in the Odoo access rights of the user the API key belongs to, where the Odoo server enforces it.

Database and login: when you must set them

Only ODOO_BASE_URL and ODOO_API_KEY are required everywhere. ODOO_DB and ODOO_USER are discovered, and whether that discovery can succeed depends on how your instance is hosted.

The database is looked for in two steps, in this order: list() on /xmlrpc/db, then a /web/session/get_session_info POST, which needs no credentials and still reports the database name when list_db = False hides the first one. The login is never asked for — an API key belongs to exactly one user, and execute_kw accepts it only with that user's uid, so the client finds the owner by probing res.users for uid 1 through 59.

Hosting

ODOO_DB

ODOO_USER

Why

Odoo Online (*.odoo.com, SaaS)

Required

Optional

Measured: the database-list endpoint is disabled there, and without the name every tool call fails with an opaque "Error executing tool" that gives no hint the database is the problem. The SaaS name is not the subdomain — it carries a suffix, in the shape mycompany16-prod-12345678, and you find it at /web/database/selector.

Odoo.sh

Optional

Optional

A branch serves one database, and the session-info fallback reports its name. Untested against a live branch: set it if the first call fails.

On-premise, one database

Optional

Optional

Discovery returns the single name, from either step.

On-premise, several databases

Optional, but convenient

Optional

Not required: the discovery error names the databases it found and tells you to pick one, so the failure is self-explanatory. Setting it skips that round trip and removes the ambiguity.

ODOO_USER is never mandatory by itself, on any hosting. Setting it saves up to 59 discovery round trips on the first call of a session, and it becomes required when the API key owner's uid is 60 or higher, because discovery only probes uid 1 to 59. It must be the login (e.g. jane@mycompany.com), and a wrong value is quiet in a way that misleads: Odoo's authenticate() returns False for an unknown login rather than raising, so a typo reads like a permission error and not like a typo.

By Odoo version

Odoo 14 through 18 behave identically here. XML-RPC carries the database name in every execute_kw call, so the client must know it before it can authenticate at all — which is exactly why discovery exists.

Odoo 19 adds the JSON-2 API, which selects the database with an X-Odoo-Database HTTP header. The header table on Odoo's own page lists it as optional, and the page's Database section is specific about when it stops being: it is "required when a single Odoo server hosts multiple databases and the dbfilter wasn't configured to use the Host header", or, as the same page puts it elsewhere, the database "must only be provided (via the X-Odoo-Database HTTP header) on systems where there are multiple databases available for a same domain". Where the hostname already picks the database — Odoo Online, Odoo.sh, any dbfilter keyed on Host — it can be left out.

This server's client tries JSON-2 first: one POST /json/2/res.users/search_count carrying Authorization: Bearer <key>, and a 200 makes JSON-2 the transport for the session; anything else falls back to XML-RPC. It sends Authorization and Content-Type and nothing else, so it does not set X-Odoo-Database — over JSON-2 the host has to resolve the database itself, and ODOO_DB reaches only the XML-RPC path.

Odoo Version Support

Odoo 14.0 is the absolute minimum supported version because this server authenticates using API keys only, which do not exist in Odoo 13 or earlier.

Odoo Version

API Keys

XML-RPC

Officially Maintained (Aug 2026)

Support Level / Notes

≤ 13.0

No

Yes

No

Unsupported. API keys do not exist, so this server cannot authenticate.

14.0

Yes

Yes

No

Protocol-compatible. Untested against a live instance.

15.0

Yes

Yes

No

Protocol-compatible. Untested against a live instance.

16.0

Yes

Yes

No

Verified against a live Enterprise instance: connection, authentication, reads, instance_overview and the Discuss tools. Two generational differences are handled for you — see the note below. Write scenarios were not exercised.

17.0

Yes

Yes

Yes (until Sep 2026)

Protocol-compatible. Untested against a live instance.

18.0

Yes

Yes

Yes (until Sep 2027)

Primary target. Verified and fully supported against a live instance.

19.0

Yes

Yes

Yes (until Sep 2028)

Protocol-compatible. Untested against a live instance. API keys require description and expiry (max 3 months). The JSON-2 API selects the database with an X-Odoo-Database header — see "Database and login: when you must set them" above.

Two things changed between Odoo 16 and 17, and neither needs configuration:

  • Discuss was renamed. mail.channel / mail.channel.member became discuss.channel / discuss.channel.member in 17. The server asks the instance which pair it has and uses that, so the four Discuss tools work on both generations.

  • Subscriptions moved onto sale.order, which before 17 had no subscription_state field at all. On 16 that section is simply absent from instance_overview — an absence, not a failure.

API Key Generation Path

To generate an API key, log in to your Odoo instance and navigate to: Preferences / My Profile → Account Security → New API Key

The illustrated walkthrough is docs/api-key.md, which also covers the duration field, the Odoo 19 expiry rule and how to revoke a key.

Transport & Deprecation Note

The client automatically detects if the native JSON-2 API is available at /json/2/<model>/<method> (which uses Authorization: bearer <API_KEY>) and falls back to XML-RPC if it is not. Please note that XML-RPC and JSON-RPC are deprecated in Odoo 19 and scheduled for removal in Odoo 22.

Sources

Tools and Resources

The server exposes 22 tools and 2 resource types:

Tools

  1. search_read: Search and read records in one call (Odoo search_read).

  2. read_record: Read one record by id, always with named fields.

  3. read_long_field: Read one long text field in windows, so a value larger than the 5000-character result cap stays readable to the end.

  4. count_records: Count the records matching a domain (Odoo search_count).

  5. group_records: Group records and count (or aggregate) per bucket in one call (Odoo read_group) — totals per state, stage or month.

  6. instance_overview: Summarise the connected instance: version, companies, volumes per area, in-house modules, anomalies.

  7. required_fields: List what Odoo demands before a create on a model, the default it would apply, and how existing records actually use it.

  8. describe_model: List a model's fields as the live instance defines them: names, types, relations, selection values, required marked.

  9. create_record: Create a record, reusing an existing match when unique_on is given.

  10. write_record: Write field values to one record and report what actually changed.

  11. run_action: Run a workflow method and report the state it left behind.

  12. cancel_record: Cancel a record through action_cancel, following the wizard it returns.

  13. notify_user: Notify users on a record's chatter. Internal by default.

  14. create_activity: Schedule an activity: the only notification that carries a deadline.

  15. download_docs: Save every document of a record to disk, chatter files included.

  16. generate_pdf: Render the PDF of a record and return where it was saved.

  17. list_message_targets: List who can be messaged and where, including internal users with presence (online/away/offline) and the caller's open conversations. Ask this before sending.

  18. read_conversation: Read a Discuss conversation, newest first.

  19. send_direct_message: Send a 1-to-1 Discuss message that appears in the user's chat systray in real time. This sends no email and reaches them whatever their notification setting says.

  20. send_channel_message: Post to an existing Discuss channel, refusing a room that holds a non-employee.

  21. explore_module: Discover a module's structure by interrogating the live instance.

  22. list_known_modules: List the modules this server has learned: name, generation date, records.

Tools 13-14 (notify_user, create_activity) notify ABOUT a record and land in the Inbox bell; tools 17-20 are Discuss conversations that land in the chat systray. "Message user X" is the second kind, which uses send_direct_message, not notify_user.

Resources

  • odoo://skill: Access the Odoo assistant skill instructions.

  • odoo://ref/*: Access generated reference documentation for explored modules.

Host Configuration Examples

Every example below carries only what matters: the two required variables, and the database, which discovery cannot reach on Odoo Online. The login is discovered, and the gate keeps its defaults unless you add ODOO_MCP_ALLOW or ODOO_MCP_DENY — see "What the agent may do". Note the quotes: environment values are strings.

ODOO_DB appears in every snippet because it is the variable most people are missing when nothing works. Set it only when required — see "Database and login: when you must set them" above. JSON allows no comments, so that note lives here rather than inside the blocks; the TOML and YAML snippets carry it inline.

Each snippet below was checked against that host's own documentation, cited on the Source: line under it. Where a host has a one-line add command, it is given as well, because it writes the same entry without a hand-edited file.

Hosted server: Claude.ai, ChatGPT and Codex

Everything in the sections below runs the server on your machine. There is a second way into the same 22 tools: they are also served over the internet at https://mcp.singleflo.com/mcp, which Claude.ai, ChatGPT and Codex can reach directly. Nothing is installed and no environment variables are set on your side — you sign in once with your Odoo address and API key, on the server's consent page, and the chat you already use reaches your Odoo. The local configuration of every other section keeps working exactly as written; the two ways differ only in where the server runs.

The consent page asks for your Odoo URL, your API key, and one choice: read lets the agent look at your data, standard lets it also create records, run workflows and schedule activities. Deletion is never available through the hosted server — unlink is not reachable from it under either choice. The choice can be changed later by signing in again and picking the other one.

Two optional fields sit alongside them, for the same reasons ODOO_DB and ODOO_USER exist locally: the database, required on Odoo Online, and the Odoo login of the user the key belongs to. Leave the login empty and the server works the owner out by probing uid 1 to 59; fill it in when that probe cannot reach — a user created well after the instance was set up sits past uid 59, and there the sign-in fails until the login is given. The page says so when it happens.

What the hosted server stores: your Odoo URL and API key, encrypted at rest; your sign-in identity, kept only as a hash; and the files a tool produces, which live there only as links that expire after fifteen minutes. The details are at https://mcp.singleflo.com/privacy, with https://mcp.singleflo.com/terms and https://mcp.singleflo.com/support on the same domain.

Per-host instructions: Claude.ai and ChatGPT are hosted-only connections and have their own sections below. Claude Code and Codex keep their local configuration above and gained a hosted one-liner each.

If you would rather run the hosted part yourself, the developer guide at docs/REMOTE.md covers the whole path — local run, tunnel, deployment.

Claude Desktop

Claude Desktop ships for macOS and Windows only, and keeps its servers in claude_desktop_config.json. Reach it from Settings → Developer → Edit Config, or edit it where it lives:

  • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json

  • Windows: %APPDATA%\Claude\claude_desktop_config.json

{
  "mcpServers": {
    "odoo-assistant": {
      "command": "uvx",
      "args": [
        "odoo-assistant"
      ],
      "env": {
        "ODOO_BASE_URL": "https://mycompany.odoo.com",
        "ODOO_API_KEY": "your-api-key-here",
        "ODOO_DB": "mycompany16-prod-12345678"
      }
    }
  }
}

Quit Claude Desktop completely and reopen it: it reads the file at startup and does not reload it. Server logs land in ~/Library/Logs/Claude/ on macOS and %APPDATA%\Claude\logs on Windows, one file per server, and stdio servers write everything they say to stderr there.

Source: https://modelcontextprotocol.io/docs/develop/connect-local-servers

Claude Code

One line adds the server. The -- separates Claude Code's own options from the command that starts the server, and everything after it is passed through untouched:

claude mcp add --env ODOO_BASE_URL=https://mycompany.odoo.com \
  --env ODOO_API_KEY=your-api-key-here \
  --env ODOO_DB=mycompany16-prod-12345678 \
  --transport stdio odoo-assistant -- uvx odoo-assistant

Note the order. --env takes KEY=value pairs and keeps reading them, so the server name must not follow it directly — put at least one other option, here --transport stdio, in between, or the CLI reads odoo-assistant as another pair and rejects it.

--scope decides where the entry lands: local (the default: this project, you only), project (.mcp.json at the repo root, committed and shared), or user (every project). To write it by hand, the same entry goes under mcpServers in .mcp.json or in ~/.claude.json:

{
  "mcpServers": {
    "odoo-assistant": {
      "command": "uvx",
      "args": [
        "odoo-assistant"
      ],
      "env": {
        "ODOO_BASE_URL": "https://mycompany.odoo.com",
        "ODOO_API_KEY": "your-api-key-here",
        "ODOO_DB": "mycompany16-prod-12345678"
      },
      "timeout": 120000
    }
  }
}

The per-server timeout is a wall-clock limit per tool call, in milliseconds, and overrides the MCP_TOOL_TIMEOUT environment variable for this server alone; MCP_TIMEOUT, also milliseconds, bounds server startup instead. Neither matters here except on the first instance_overview call of a session, which pays for authentication plus dozens of XML-RPC round trips. Reconnect the server from the /mcp panel after editing, or restart Claude Code.

The one-liner above runs the server on your machine. Claude Code can also use the hosted server — no install, no environment variables:

claude mcp add --transport http odoo-assistant https://mcp.singleflo.com/mcp

The first tool call starts the sign-in and lands on the consent page, where read or standard is chosen. On the hosted route the gate is decided there, not by local ODOO_MCP_* variables, and deletion is not offered at all.

Source: https://code.claude.com/docs/en/mcp

OpenAI Codex CLI

Codex keeps MCP servers in TOML, in ~/.codex/config.toml, or in a project's .codex/config.toml once you have trusted that project. The table is spelled with an underscore — mcp_servers, not mcp.servers. The ChatGPT desktop app, the Codex CLI and the IDE extension all read this one file, so configuring it once covers the three.

codex mcp add odoo-assistant \
  --env ODOO_BASE_URL=https://mycompany.odoo.com \
  --env ODOO_API_KEY=your-api-key-here \
  --env ODOO_DB=mycompany16-prod-12345678 \
  -- uvx odoo-assistant

The same entry written out:

[mcp_servers.odoo-assistant]
command = "uvx"
args = ["odoo-assistant"]
startup_timeout_sec = 30
tool_timeout_sec = 300

[mcp_servers.odoo-assistant.env]
ODOO_BASE_URL = "https://mycompany.odoo.com"
ODOO_API_KEY = "your-api-key-here"
# only when required, see "Database and login" above
ODOO_DB = "mycompany16-prod-12345678"

Both timeouts are in seconds: startup_timeout_sec defaults to 10 and tool_timeout_sec to 60. Only the first instance_overview call comes near either, which is why both are raised above. After editing, press Restart on the server in the desktop app or the IDE extension; in the CLI, start a new session and check it with /mcp.

The hosted server is added by URL instead, and the sign-in is its own command:

codex mcp add odoo-assistant --url https://mcp.singleflo.com/mcp
codex mcp login odoo-assistant

codex mcp login walks the same OAuth flow and lands on the consent page, where read or standard is chosen; codex mcp logout odoo-assistant ends the connection. As on every hosted route: reads always work, writes follow the choice made at sign-in, and deletion is not available at all.

Source: https://developers.openai.com/codex/mcp

Source: https://developers.openai.com/codex/config-file/config-reference

ChatGPT

ChatGPT reaches the hosted server through developer mode, available to Pro, Plus, Business, Enterprise and Education accounts, on the web:

  1. In ChatGPT, open Settings → Security and login and turn on Developer mode.

  2. Open chatgpt.com/plugins, press the plus button and create a developer-mode app for the MCP URL https://mcp.singleflo.com/mcp.

  3. ChatGPT starts the sign-in, which lands on the server's consent page: enter your Odoo URL and API key and choose read or standard.

  4. In a conversation, choose Developer mode from the plus menu and select the Odoo Assistant app.

There is deliberately no local snippet here: developer mode connects to remote MCP servers over HTTPS only, so the stdio configuration of the other sections does not apply. A public listing in ChatGPT's Plugin Directory, which removes the developer-mode step, is planned but has not arrived yet.

What the agent may do is decided once, at sign-in: read, or standard — never deletion, whatever the conversation asks for.

Source: https://developers.openai.com/api/docs/guides/developer-mode

Claude.ai (web, Desktop, mobile)

Claude connects to the hosted server as a custom connector. Open Customize → Connectors → Add custom connector, paste https://mcp.singleflo.com/mcp as the server URL and confirm. On Team and Enterprise plans an owner adds it once under Organization settings → Connectors; members then connect from Customize → Connectors.

The first use starts the sign-in, which lands on the consent page: your Odoo URL, your API key, and the read-or-standard choice.

This link opens the same dialog with the name and URL already filled in — review them and confirm; nothing is added until you do:

https://claude.ai/customize/connectors?modal=add-custom-connector&connectorName=Odoo%20Assistant&connectorUrl=https%3A%2F%2Fmcp.singleflo.com%2Fmcp

Source: https://claude.com/docs/connectors/custom/remote-mcp

Source: https://claude.com/docs/connectors/building/directory-vs-custom

opencode

Add this to opencode.json or .opencode/opencode.json in your project, or to ~/.config/opencode/opencode.json to make the server available everywhere:

{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "odoo-assistant": {
      "type": "local",
      "enabled": true,
      "command": [
        "uvx",
        "odoo-assistant"
      ],
      "timeout": 120000,
      "environment": {
        "ODOO_BASE_URL": "https://mycompany.odoo.com",
        "ODOO_API_KEY": "your-api-key-here",
        "ODOO_DB": "mycompany16-prod-12345678"
      }
    }
  }
}

opencode's shape differs from the hosts above in ways it rejects outright. The key is mcp (not mcpServers), type is required, command is a single array holding the program and its arguments (there is no separate args), and the environment block is environment (not env).

Set timeout deliberately. It defaults to 5000 ms. The first call of a session pays for authentication plus, for instance_overview, dozens of XML-RPC round trips, which easily exceeds five seconds against a real instance. Set it to 120000.

opencode reads its config once at startup and does not hot-reload it. Quit and restart after editing. Anything you change here, the allow and deny lists included, takes effect only on the next launch.

Source: https://opencode.ai/docs/mcp-servers

Hermes

Hermes keeps its servers in YAML, under mcp_servers: in ~/.hermes/config.yaml:

mcp_servers:
  odoo-assistant:
    command: /Users/you/.local/bin/uvx
    args:
      - odoo-assistant
    env:
      ODOO_BASE_URL: https://mycompany.odoo.com
      ODOO_API_KEY: your-api-key-here
      # only when required, see "Database and login" above
      ODOO_DB: mycompany16-prod-12345678
    timeout: 120
    connect_timeout: 60
    enabled: true

Three details this shape does not forgive. command is a string and takes only the program, with the arguments in a separate args list — the opposite of opencode's single array. The environment block is env. And the command needs an absolute path: Hermes runs as a desktop application, which does not inherit the PATH of your shell, so a bare uvx is not found.

Both timeouts here are in seconds, not milliseconds: timeout is the tool-call limit and defaults to 300, connect_timeout bounds the initial connection and defaults to 60. The 120 above is comfortably more than the first instance_overview call needs. Reload the servers with /reload-mcp after editing rather than restarting.

hermes mcp add can write this entry for you — its signature is add <name> [--url URL] [--command CMD] [--auth oauth|header] [--args ...] — but pass --args last: it takes the remaining argv, so anything after it is swallowed into args, which is how credentials end up there and the server starts with none.

Source: https://hermes-agent.nousresearch.com/docs/reference/mcp-config-reference

Cursor

Add this to .cursor/mcp.json in your project, to ~/.cursor/mcp.json to make the server available everywhere, or configure it from Customize in the sidebar:

{
  "mcpServers": {
    "odoo-assistant": {
      "command": "uvx",
      "args": [
        "odoo-assistant"
      ],
      "env": {
        "ODOO_BASE_URL": "https://mycompany.odoo.com",
        "ODOO_API_KEY": "your-api-key-here",
        "ODOO_DB": "mycompany16-prod-12345678"
      }
    }
  }
}

Cursor interpolates ${env:NAME} inside command, args, env, url and headers, so "ODOO_API_KEY": "${env:ODOO_API_KEY}" keeps the key out of a file you might commit. When a call fails, the reason is in the Output panel under MCP Logs.

Source: https://cursor.com/docs/context/mcp

Windsurf

Windsurf's Cascade agent reads one global file — ~/.codeium/windsurf/mcp_config.json — on every platform. There is no project-scoped equivalent, so this entry applies to every workspace you open:

{
  "mcpServers": {
    "odoo-assistant": {
      "command": "uvx",
      "args": [
        "odoo-assistant"
      ],
      "env": {
        "ODOO_BASE_URL": "https://mycompany.odoo.com",
        "ODOO_API_KEY": "your-api-key-here",
        "ODOO_DB": "mycompany16-prod-12345678"
      }
    }
  }
}

Open it from the MCPs icon in the Cascade panel, or from Settings → Cascade → MCP Servers, then refresh the server list. The file interpolates ${env:VAR_NAME} and ${file:/path/to/file} in command, args and env, so the API key can live outside it. Cascade caps the agent at 100 tools in total, and this server contributes 22.

Source: https://docs.windsurf.com/windsurf/cascade/mcp

VS Code and GitHub Copilot

VS Code's root key is servers, not mcpServers — an entry copied from another host's documentation will not be seen. Put it in .vscode/mcp.json in your workspace, to commit it with the project, or run MCP: Open User Configuration from the Command Palette for the copy that follows your user profile into every workspace:

{
  "servers": {
    "odoo-assistant": {
      "type": "stdio",
      "command": "uvx",
      "args": [
        "odoo-assistant"
      ],
      "env": {
        "ODOO_BASE_URL": "https://mycompany.odoo.com",
        "ODOO_API_KEY": "your-api-key-here",
        "ODOO_DB": "mycompany16-prod-12345678"
      }
    }
  }
}

The command line writes the same entry:

code --add-mcp "{\"name\":\"odoo-assistant\",\"command\":\"uvx\",\"args\":[\"odoo-assistant\"]}"

The first time VS Code starts a server it asks whether you trust it; decline and the server never runs. Use the code lenses in mcp.json, or MCP: List Servers in the Command Palette, to start, stop and restart it and to read its output. Avoid hardcoding the API key in a committed workspace file — VS Code provides input variables for exactly this.

Source: https://code.visualstudio.com/docs/copilot/customization/mcp-servers

Gemini CLI

Gemini CLI reads mcpServers from settings.json: ~/.gemini/settings.json for every session, or .gemini/settings.json in a project's root for that project only, which takes precedence.

gemini mcp add odoo-assistant uvx odoo-assistant \
  --env ODOO_BASE_URL=https://mycompany.odoo.com \
  --env ODOO_API_KEY=your-api-key-here \
  --env ODOO_DB=mycompany16-prod-12345678 \
  --scope user

The same entry written out:

{
  "mcpServers": {
    "odoo-assistant": {
      "command": "uvx",
      "args": [
        "odoo-assistant"
      ],
      "env": {
        "ODOO_BASE_URL": "https://mycompany.odoo.com",
        "ODOO_API_KEY": "your-api-key-here",
        "ODOO_DB": "mycompany16-prod-12345678"
      },
      "timeout": 600000
    }
  }
}

timeout is the request timeout in milliseconds and already defaults to 600000, ten minutes, so the first instance_overview call needs nothing from you here; the line is shown only because it is the key to lower if you want a faster failure. Two other habits pay off: Gemini CLI redacts anything matching *KEY*, *TOKEN* or *SECRET* from the inherited environment before spawning a server, so a variable must be named in this env block to arrive at all, and "$MY_VAR" inside it expands from your shell. Restart the CLI after editing, then check the server with /mcp.

Source: https://github.com/google-gemini/gemini-cli/blob/main/docs/tools/mcp-server.md

Source: https://github.com/google-gemini/gemini-cli/blob/main/docs/cli/cli-reference.md

Cline

Cline's CLI reads ~/.cline/mcp.json. In the IDE extensions, open the MCP Servers icon in the Cline panel, go to the Configure tab and press Configure MCP Servers, which opens the extension's own settings JSON. Both use the same mcpServers shape:

{
  "mcpServers": {
    "odoo-assistant": {
      "command": "uvx",
      "args": [
        "odoo-assistant"
      ],
      "env": {
        "ODOO_BASE_URL": "https://mycompany.odoo.com",
        "ODOO_API_KEY": "your-api-key-here",
        "ODOO_DB": "mycompany16-prod-12345678"
      },
      "disabled": false,
      "autoApprove": []
    }
  }
}

Leave autoApprove empty. It is the list of tools that run without asking, and the gate in this server is not a substitute for reading a write call before it happens. cline mcp opens an interactive wizard that adds, edits, enables and removes servers without touching the file. The request timeout is a per-server setting in the MCP settings panel rather than a key in this file — raise it there if the first instance_overview call times out, and restart the server from the same panel.

Source: https://docs.cline.bot/mcp/mcp-overview

Roo Code

Roo Code reads two files: a global mcp_settings.json, opened by the Edit Global MCP button at the bottom of the MCP settings view, and a per-project .roo/mcp.json opened by Edit Project MCP next to it, which Roo creates if it does not exist. A server name present in both takes its project definition.

{
  "mcpServers": {
    "odoo-assistant": {
      "command": "uvx",
      "args": [
        "odoo-assistant"
      ],
      "env": {
        "ODOO_BASE_URL": "https://mycompany.odoo.com",
        "ODOO_API_KEY": "your-api-key-here",
        "ODOO_DB": "mycompany16-prod-12345678"
      },
      "alwaysAllow": [],
      "disabled": false,
      "timeout": 300
    }
  }
}

timeout here is in seconds, not milliseconds — it accepts 1 to 3600 and defaults to 60. Sixty is enough for every call but the first instance_overview of a session, which is the one to raise it for; the same value is the Network Timeout dropdown in the server's own panel. Leave alwaysAllow empty, for the reason given under Cline. Press the restart button next to the server after editing.

Committing .roo/mcp.json shares the server with your team — so put the API key in a system environment variable and reference it as ${env:ODOO_API_KEY} inside args, rather than writing it into a file that goes into version control.

Source: https://docs.roocode.com/features/mcp/using-mcp-in-roo

Zed

Zed calls them context servers, and the key is context_servers, not mcpServers. Add the entry to your settings file — Command Palette, zed: open settings file — or let Zed write it for you from Settings → AI → MCP Servers → Add Server → Add Local Server:

{
  "context_servers": {
    "odoo-assistant": {
      "command": "uvx",
      "args": [
        "odoo-assistant"
      ],
      "env": {
        "ODOO_BASE_URL": "https://mycompany.odoo.com",
        "ODOO_API_KEY": "your-api-key-here",
        "ODOO_DB": "mycompany16-prod-12345678"
      }
    }
  }
}

The indicator dot beside the server's name in Settings → AI → MCP Servers says whether it came up: green, with "Server is active" in its tooltip, means Zed reached it. Tool approval is governed by agent.tool_permissions.default, which is "confirm" by default; per-tool rules use the key format mcp:odoo-assistant:<tool_name>, for example mcp:odoo-assistant:search_read.

Source: https://zed.dev/docs/ai/mcp

JetBrains AI Assistant

JetBrains AI Assistant takes the configuration through a dialog rather than a file you locate yourself. Go to Settings | Tools | AI Assistant | Model Context Protocol (MCP), click Add, choose STDIO, and paste this as the JSON configuration:

{
  "mcpServers": {
    "odoo-assistant": {
      "command": "uvx",
      "args": [
        "odoo-assistant"
      ],
      "env": {
        "ODOO_BASE_URL": "https://mycompany.odoo.com",
        "ODOO_API_KEY": "your-api-key-here",
        "ODOO_DB": "mycompany16-prod-12345678"
      }
    }
  }
}

The dialog documents command and args, and adds two fields of its own beside the JSON: Working directory, and Server level, which decides whether the server is available globally or only in the current project. Click OK, then Apply — that is what actually starts the server, and the Status column reports whether it connected. If you already have this server in Claude Desktop, Import from Claude carries the whole entry over instead, including its environment block.

Source: https://www.jetbrains.com/help/ai-assistant/mcp.html

Odoo Online Production (Read-Only Example)

If you are connecting to a production instance hosted on Odoo Online (SaaS), you must set ODOO_DB and should set ODOO_MCP_ALLOW to "none" for safety. Here is how it looks in Claude Desktop:

{
  "mcpServers": {
    "odoo-assistant": {
      "command": "uvx",
      "args": [
        "odoo-assistant"
      ],
      "env": {
        "ODOO_BASE_URL": "https://mycompany.odoo.com",
        "ODOO_API_KEY": "your-api-key-here",
        "ODOO_DB": "mycompany16-prod-12345678",
        "ODOO_MCP_ALLOW": "none"
      }
    }
  }
}

Setting ODOO_DB is mandatory to bypass the disabled database-list endpoint on Odoo Online, while ODOO_MCP_ALLOW set to "none" ensures the agent cannot modify live production data.

The examples omit the optional variables. Set ODOO_DB when the instance serves several databases, ODOO_USER — the login, e.g. jane@mycompany.com — to skip the uid probe, and ODOO_MCP_ALLOW / ODOO_MCP_DENY when the gate's defaults — every method but the seven denied ones — are not what you want.

Changelog

What changed in each release is in CHANGELOG.md, kept there rather than repeated here so the two cannot drift.

License

This project is licensed under the MIT License. See the LICENSE file for details.

Available Tools

19 tools
cancel_recordC
Destructive

Cancel a record through action_cancel, following the wizard it returns.

Destructive, so the default ceiling refuses it and says what would not.

ParametersJSON Schema
NameRequiredDescriptionDefault
modelYes
record_idYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

C2/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare destructiveHint=true, so the description's repetition of 'destructive' adds limited value. However, it introduces the behavioral nuance that 'the default ceiling refuses it and says what would not', which tells agents that the tool may be blocked and explains why. This is useful context beyond the annotation, but the phrase 'following the wizard it returns' remains cryptic.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness2/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is short but not clear or well-structured. The first sentence is technical ('through `action_cancel`'), and the second sentence is confusing ('says what would not'). Conciseness without clarity is counterproductive.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness1/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The tool has 2 required parameters, a destructive annotation, an output schema, and 18 sibling tools. The description fails to cover how the parameters affect behavior, what the output contains (despite having an output schema), or how this tool fits into the broader workflow. It is grossly insufficient for an agent to use correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters1/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema has 0% description coverage, so the description must explain all parameters. It does not: neither 'model' nor 'record_id' are described. The description contains zero parameter guidance, leaving the agent to guess what values are expected or valid.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose2/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states 'Cancel a record' but fails to specify what kind of record, in which domain, or how it differs from sibling tools like 'write_record' or 'run_action'. The phrase 'through `action_cancel`' is jargon and doesn't clarify the scope, making the purpose vague and poorly communicated.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides no guidance on when to use this tool versus alternatives. While it mentions 'destructive' and a 'default ceiling refuses it', it does not explain which scenarios warrant cancellation or when a non-destructive alternative (like 'write_record') would be more appropriate. The context is entirely absent.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

count_recordsA

Count the records matching a domain (Odoo search_count).

A count is only as honest as its domain:

  • account.move / account.move.line without a move_type filter is refused — it would count invoices, bills, credit notes and journal entries together and match no figure the user has ever seen.

  • A count answers "how many", never "how much". For an amount, read amount_total_signed (company currency) and never amount_total.

  • On a multi-company instance the count differs per company: pass company_ids or you are reporting one company as the whole business.

Args: model: Odoo model, e.g. "crm.lead". domain: Odoo domain. Omit to count everything the model holds. company_ids: Companies to count in, e.g. [1, 2].

ParametersJSON Schema
NameRequiredDescriptionDefault
modelYes
domainNo
company_idsNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.4/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries full transparency burden. It discloses behavioral traits (e.g., refuses certain domains, counts per company), but does not mention side effects, performance, or immutability. The description adds value beyond what annotations would provide, but lacks a complete behavioral profile.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with purpose, uses bullet points for clarity, and is efficient. However, the bullet points could be slightly condensed; some phrases (e.g., 'A count is only as honest as its domain') add style but length. Overall well-structured and concise.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the complexity (counting with domain pitfalls), 3 parameters, and presence of an output schema, the description covers key usage scenarios and edge cases. It lacks details on return value (though output schema exists) and specific error conditions, but is largely complete for effective agent use.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate, and it does so excellently. The docstring explains each parameter's semantics, providing examples or clarifying defaults (e.g., 'omit to count everything' for domain, and company_ids for multi-company). It adds meaningful context beyond the schema's type definitions.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a clear verb 'count' with the resource 'records matching a domain' and explicitly links it to the Odoo `search_count` method. It clearly distinguishes from siblings like `search_read` (which returns records) and establishes its scope as a counting operation.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides explicit guidance on when and when not to use the tool, including warnings about mixing `move_type`, confusing count with sum, and multi-company instances. It effectively helps the agent avoid common mistakes by specifying exclusions and context.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

create_activityA

Schedule an activity: the only notification that carries a deadline.

A chatter note is passive. An activity appears in the assignee's To-Do list and turns overdue when the date passes.

Args: model: the Odoo model, e.g. "crm.lead". record_id: id of the record the activity hangs off. summary: the one-line title the assignee will read. user_id: res.users id of the assignee. days: deadline offset from today, in days. activity_type: substring of an activity type name, e.g. "call". Activity types differ per instance; the first available type is used when this is omitted or matches nothing.

ParametersJSON Schema
NameRequiredDescriptionDefault
daysNo
modelYes
summaryYes
user_idYes
record_idYes
activity_typeNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden of behavioral disclosure. It clearly states that the activity appears in a To-Do list and turns overdue, and that activity type resolution is fuzzy (substring match, fallback to first available). The mutation nature (scheduling) is evident, though it could mention if this a destructive action (e.g., cannot be undone) or any permission requirements.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is compact, front-loaded with a clear purpose, and uses a concise bullet-style list for parameters. Every sentence adds distinct value—no filler, no redundancy, easy to scan.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Despite having an output schema, the description does not explain what the tool returns (e.g., the created activity ID). However, for a creation tool, the primary concern is correct invocation, which the description handles well. The lack of return value explanation is a minor gap, but the tool's purpose is still fully actionable.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate. It explains the purpose of each parameter in a sentence, adding context beyond the schema titles (e.g., 'deadline offset', 'the one-line title the assignee will read', 'substring of an activity type name'). This gives the agent sufficient guidance for correct invocation.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description specifies the verb 'schedule' and the resource 'activity' with a clear distinction from a 'chatter note'. It highlights the unique characteristic (deadline) that differentiates it from other notification tools, giving the agent a precise sense of what this tool does.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly contrasts an activity with a chatter note (sibling notify_user), explaining when to use this tool over a passive notification. However, it does not explicitly list other sibling tools as alternatives or state when not to use it beyond that one distinction.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

create_recordA

Create a record, reusing an existing match when unique_on is given.

unique_on is a list of FIELD NAMES taken from values (e.g. ["name", "email"]): they are searched first and the existing id comes back instead of a duplicate. Odoo has no idempotency key, so a create that is retried is simply a second record — this is the only protection there is, and a cold-start run without it produced four identical customers.

Multi-company: put company_id in values. The context decides what is visible, not which company owns the new record.

ParametersJSON Schema
NameRequiredDescriptionDefault
modelYes
valuesYes
unique_onNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description adds substantial context beyond annotations: the search-and-return behavior of unique_on, the lack of Odoo idempotency keys, and multi-company visibility nuances. This complements the readOnlyHint and idempotentHint annotations without contradiction.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is efficiently structured with front-loaded purpose, followed by essential behavioral and usage details. Every sentence contributes meaningfully, avoiding unnecessary verbosity.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the existence of an output schema, the description appropriately focuses on input semantics and behavioral traits. It covers idempotency, dedup, and multi-company scenarios, which are critical for correct tool invocation. No gaps remain for the intended usage.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With 0% schema description coverage, the description compensates well for unique_on (list of field names, dedup logic) and values (company_id guidance). Only the model parameter lacks explicit description, but its purpose is clear from context.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the verb 'Create' and the resource 'record', and immediately highlights the key deduplication feature with unique_on. This distinguishes it from sibling tools like write_record (update) and read_record (read).

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Guidance is provided on when to use unique_on (to avoid duplicates) and when retries cause duplicates due to lack of idempotency key. Multi-company handling is explained. However, explicit comparison to write_record or when not to use the tool is missing.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

download_docsA

Save every document of a record to disk — chatter files included.

Returns {"saved": [paths], "skipped": [[name, why]]}. skipped is not noise: a database restored without its filestore keeps the attachment rows and loses the bytes, and an empty result would read exactly like "this record has no attachments".

Args: model: the Odoo model, e.g. "account.move". record_id: id of the record whose documents to fetch. dest_dir: directory to write the files into. Defaults to this platform's temporary directory — "/tmp" does not exist on Windows.

ParametersJSON Schema
NameRequiredDescriptionDefault
modelYes
dest_dirNo
record_idYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.6/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden. It discloses key behaviors: saving to disk, including chatter files, returning saved/skipped lists, and platform-specific temp directory behavior. It does not mention file overwrite policy or permissions, but for a download tool this is reasonably transparent.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is efficiently structured: first sentence states purpose and key nuance, second paragraph explains return format with a useful warning about skipped files, third paragraph details each parameter. Every sentence adds necessary information without repetition.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's three parameters and no annotations, the description covers purpose, parameter details, return format, and important edge cases. The output schema is not shown but the description describes it adequately. The tool is fully explained for an AI agent to use correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate. It provides clear meanings for all three parameters: model (with example), record_id (purpose), and dest_dir (default behavior and Windows caveat). This adds significant value beyond the bare schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the verb-resource combination: 'Save every document of a record to disk — chatter files included.' It is specific about including chatter files, which distinguishes it from any sibling tool that might handle documents differently.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides context on when the tool is relevant by explaining edge cases of skipped documents (database restore without filestore) and the default behavior of dest_dir. However, it does not explicitly define when to use this tool versus alternatives or when not to use it.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

explore_moduleB

Discover a module's structure by interrogating the live instance.

Args: module_name: Module to explore, e.g. "helpdesk". Must be a module slug, since it names the reference file on "generate"; ignored on "list". action: "generate" (the default) writes the reference document, "list" ranks what is worth exploring. models: Comma-separated models for a module the script does not know, e.g. "superchat.message,superchat.template". Defaults to the script's own grouping for module_name.

ParametersJSON Schema
NameRequiredDescriptionDefault
actionNogenerate
modelsNo
module_nameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

B3.1/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description must fully disclose behavioral traits. It mentions actions (writes reference document vs. ranks) but does not clarify side effects (e.g., does 'generate' modify the system?), read vs. write nature, or required permissions. This leaves significant ambiguity for a tool that appears to produce artifacts.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with a clear purpose sentence, followed by a structured parameter block. Each parameter gets a concise explanation. No redundant information. Could be slightly more compact but remains efficient.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists but the description neither references nor explains return values (especially for 'list' action). It covers parameter behavior adequately but omits error conditions, prerequisites (e.g., is the module installed?), and the structure of the generated document. Some gaps remain despite reasonable param coverage.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0%, so description must compensate. It explains module_name is a slug and ignored on 'list', actions define output behavior, and models provides comma-separated overrides. This adds essential meaning beyond the schema's bare defaults and types.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool discovers a module's structure by interrogating the live instance, with specific actions (generate/list). This distinguishes it from sibling tools like list_known_modules which likely only lists module names, though it could be more precise about 'structure' meaning.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No explicit guidance on when to use this tool versus alternatives, such as comparing with search_read or list_known_modules. The description does not advise on choosing between 'generate' and 'list' actions beyond defining them, and omits any when-not-to-use scenarios.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

generate_pdfA

Render the PDF of a record and return where it was saved.

An already rendered PDF is reused. Otherwise the model's own print/send wizard produces it, and that wizard can also SEND the document — which is why this is gated on action_send_and_print (L3_STATE_CHANGE) rather than as a plain read.

Args: model: the Odoo model, e.g. "account.move". record_id: id of the record to print. dest_dir: directory to write the PDF into. Defaults to this platform's temporary directory — "/tmp" does not exist on Windows.

ParametersJSON Schema
NameRequiredDescriptionDefault
modelYes
dest_dirNo
record_idYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.6/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden of behavioral disclosure. It reveals that already rendered PDFs are reused, that the print/send wizard can trigger document sending (a side effect), and that the tool is classified as a state change (L3_STATE_CHANGE) rather than a read. It also notes a cross-platform directory default. Missing are details about error handling or what happens if the wizard fails, but the disclosed traits are significant and useful.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is concise (about 100 words) and well-structured. It opens with a clear one-sentence summary, then adds necessary context about reuse, permissions, and side effects, and closes with a bullet-style parameter list. Every sentence adds value, with no redundancy or filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity (3 parameters, potential side effect, no annotations), the description is remarkably complete. All parameters are explained, the behavioral nuance (caching, sending, permission gate) is disclosed, and the output schema exists to cover return values. The description does not leave obvious gaps for an agent to misuse the tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema has 0% description coverage, so the description must wholly compensate. It does so admirably with an 'Args' section: 'model' is explained with an example ('account.move'), 'record_id' is described as the ID to print, and 'dest_dir' is given a default behavior and a cross-platform warning ('/tmp does not exist on Windows'). This adds critical meaning beyond the bare schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's purpose: 'Render the PDF of a record and return where it was saved.' It uses a specific verb ('render'), identifies the resource ('PDF of a record'), and the outcome ('return where it was saved'). This uniquely distinguishes it from sibling tools which are mainly CRUD operations, so there is no confusion.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides context on when to use the tool: to obtain a PDF of a record, with the caution that the underlying wizard can also send the document, so it is gated on a specific permission. It implies usage for PDF retrieval but does not explicitly state when not to use it or list alternatives. However, given no sibling PDF tools, the guidance is sufficient.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

instance_overviewA

Summarise the connected instance: version, companies, volumes per area, in-house modules, anomalies.

The profile is built from the instance this server is CONNECTED to, and cached per instance — census.profile_path() keys it on the live client, not on an environment variable. That distinction is the whole point: with two instances profiled on one machine, choosing by ODOO_DB (which is discovered now, so often unset) once fell through to "the first file on disk" and reported a neighbour's numbers as this instance's, with no error and a perfectly plausible report.

First call against a new instance builds the profile, which costs a second or so; every later call is free. Pass refresh=True after the instance has changed — the report carries the timestamp it was taken.

When drilling into these figures, the two rules that keep them meaningful: filter account.move by move_type, and sum amount_total_signed, never amount_total.

Args: refresh: rebuild the profile from the instance instead of reusing it.

ParametersJSON Schema
NameRequiredDescriptionDefault
refreshNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries full burden for behavioral disclosure. It clearly discloses caching behavior (cached per instance, keyed on live client not environment variable), performance characteristics (first call costs ~1 second, subsequent calls free), and a detailed edge case about instance misidentification when `ODOO_DB` is unset. It also reveals that the report carries a timestamp. The only gap is that it doesn't state whether the tool is read-only or has any side effects beyond building the cache.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with a summary sentence, which is good. However, the explanation of the caching edge case, while valuable, is verbose and could be tightened. It runs to several paragraphs where two well-structured paragraphs might suffice. Every sentence earns its place in terms of content, but the prose could be more compact.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the complexity of this tool (caching behavior, potential for misidentification, performance profile, drill-down rules) and the richness of the output schema (indicated by 'has output schema: true'), the description covers all necessary ground: what it does, how the cache works, when to refresh, and how to interpret numbers. The output schema likely documents the return shape, so no further explanation is needed there. This is a complete, self-contained description.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The single parameter `refresh` has 0% schema description coverage (the schema provides only type and default), so the description must compensate. It does so excellently: it explains that `refresh=True` rebuilds the profile from the instance instead of reusing the cache, and implicitly clarifies the default behavior (cached reuse). This adds far more meaning than the bare schema provides.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a clear verb ('Summarise') and specifies the resource ('connected instance') along with a detailed list of what it covers: version, companies, volumes per area, in-house modules, anomalies. This fully distinguishes it from siblings like 'explore_module' or 'search_read', which operate on different scopes.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly explains when to use this tool (anytime you need an overview of the connected instance) and provides crucial contextual advice: use `refresh=True` after the instance changes, and mentions the cost profile (first call is expensive, subsequent calls free). It also gives rules for drilling into figures (filter `account.move` by `move_type`, sum `amount_total_signed`). However, it does not explicitly state when NOT to use it or name alternatives among the given siblings.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_known_modulesA

List the modules this server has learned: name, generation date, records.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A3.8/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries full burden. It accurately signals this is a read-only, listing operation with no side effects, and details the output fields (name, generation date, records). This is sufficient disclosure for a zero-parameter tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

At 9 words, the description is extremely concise and front-loaded with the key verb and resource. Every word is meaningful. It could optionally mention no parameters are needed, but that is implicit.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a zero-parameter, read-only listing tool with an output schema, the description is complete. It states what the tool lists and what information is returned. No critical gaps are present.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% but there are zero parameters, so the description has nothing to add about parameters. The baseline is 4 per the rubric for 0 params — description correctly says nothing about params because there are none.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the verb 'List' and the resource 'modules this server has learned', and specifies the information included: name, generation date, records. This distinguishes it from sibling tools like search_read, read_record, and explore_module by focusing on enumerating learned modules and their metadata.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies this is a discovery tool for seeing what modules the server knows about, but does not explicitly state when to use it over alternatives like explore_module or read_record. No exclusions or prerequisites are mentioned.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_message_targetsA

Who can be messaged and where — ASK THIS BEFORE SENDING ANYTHING.

Two lists in one call, because an agent that cannot see the roster invents ids:

  • users: the internal, active users, each with im_status — 'online', 'away' (idle 30 minutes) or 'offline'. Presence is worth reading first: a Discuss message is delivered either way, but "offline" tells you nobody is going to answer right now.

  • conversations: the ones the sender already belongs to and has not archived, with channel_type — 'chat' is a 1-to-1, 'group' is a private multi-party, 'channel' is a room that may hold the whole company. members and unread are there so a broadcast is a deliberate choice rather than a surprise.

Use send_direct_message for a person and send_channel_message for a conversation in this list. Neither of them is the tool for annotating an invoice or an order — that is notify_user.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.6/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Without annotations, the description carries full burden. It explains the tool returns two lists, details key fields (im_status with state definitions and timeouts, channel_type with distinctions, members, unread counts), and notes that conversations are those the sender belongs to and hasn't archived. It does not mention whether the operation is read-only or any authentication needs, but the listing nature is clear.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is longer than typical but is well-structured: a bold imperative line, followed by a clear explanation of the two lists with bullet points, and ending with usage guidance. Each sentence serves a purpose, though some details (e.g., the idle time for 'away') could be trimmed without losing core meaning.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given zero parameters, an output schema (present but not shown), and no annotations, the description provides comprehensive context: why the tool exists ('an agent that cannot see the roster invents ids'), what data it returns with field explanations, when to call it (before any send), and how to use the results with sibling tools. The only slight gap is not explicitly stating it's read-only, but that's strongly implied.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema has zero parameters, so there are no parameter semantics to describe. With 0 parameters, baseline is 4. The description focuses on output context but adds value by explaining what the returned data represents, which is helpful even though no parameters exist.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description explicitly states 'Who can be messaged and where' and breaks down the two lists: users (with presence) and conversations (with type and membership). It clearly distinguishes from sibling messaging tools like send_direct_message and send_channel_message by naming them and contrasting their roles.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description opens with 'ASK THIS BEFORE SENDING ANYTHING,' establishing when to use it. It provides conditional advice (check presence before messaging) and explicitly directs to send_direct_message for individuals and send_channel_message for conversations, while noting notify_user is for annotating invoices/orders.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

notify_userA

Write a note on a record's chatter and notify the users you name.

Both subtypes post a message that IS VISIBLE in the record's chatter. The difference is who it reaches beyond the people you name.

Args: model: the Odoo model, e.g. "sale.order". record_id: id of the record to write on. message: the body. Send PLAIN TEXT: Odoo escapes anything that arrives over RPC, so "x" is displayed as the literal characters <b>x</b>, not as bold — there is no way to pass real markup through this call, and newlines survive but are not turned into line breaks. Write the note as prose. user_ids: res.users ids to notify. They are notified each through their OWN Odoo setting, inbox or email, so naming someone is not a promise that no mail leaves. subtype: where the message lands.

    | subtype   | visible in the chatter | emails a customer |
    |-----------|------------------------|-------------------|
    | "note"    | yes, internal users    | never             |
    | "inbox"   | NO — notification only | never             |
    | "comment" | yes, everyone          | **YES**           |

    "note" posts `mail.mt_note` and is the default: measured on a real
    order it produced one inbox notification and zero emails.
    "inbox" goes through `message_notify`, which Odoo documents as the
    path for "messages that should not be displayed on a document" —
    the person is notified, the record keeps no trace. "comment" posts
    `mail.mt_comment` and is refused while an external follower
    exists, unless force=True.
force: post the comment anyway, knowing those people get an email.
ParametersJSON Schema
NameRequiredDescriptionDefault
forceNo
modelYes
messageYes
subtypeNonote
user_idsYes
record_idYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A3.9/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Since no annotations are provided, the description carries the full burden. It discloses important behaviors: message is plain text with escaped HTML, newlines survive but are not turned into line breaks, user notifications go through personal Odoo settings (inbox or email, so email is possible), and the 'comment' subtype can be forced to bypass refusal. The only flaw is the internal contradiction about 'inbox' visibility, which undermines trust slightly.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is moderately long but well-organized with a table and clear sections. The purpose is stated upfront. Each sentence adds value, though the initial visible/inbox contradiction wastes some space. For a tool with 6 parameters and nuanced behavior, this length is justified.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity (6 parameters, required fields, no output schema visible despite context saying one exists), the description adequately covers behavior but misses key context: what the tool returns (a result ID or success message?), and any prerequisites like user permissions or record access. The internal contradiction also leaves the agent uncertain about the 'inbox' subtype's behavior.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0%, so the description must add full meaning. It does so excellently: explains 'model' with an example, describes the plain-text constraint for 'message', clarifies the meaning and default of 'subtype' with a table, defines 'user_ids' as res.users ids with notification semantics, and explains the 'force' flag. Every parameter is thoroughly documented, going far beyond the bare schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states 'Write a note on a record's chatter and notify the users you name,' which accurately conveys the tool's primary purpose and distinguishes it from siblings like 'send_direct_message' or 'create_activity'. However, the initial claim that both subtypes post a visible message is contradicted later when the table shows the 'inbox' subtype is NOT visible in chatter, introducing unnecessary confusion.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides detailed guidance on when to use each subtype (note, inbox, comment) based on visibility and email behavior, which helps the agent choose the right parameter value. However, it does not offer any high-level guidance on when to use this tool versus sibling tools like 'send_direct_message' or 'create_activity', leaving the agent to infer that from the purpose alone.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

read_conversationA

Read what was said in a Discuss conversation, newest first.

This is how you answer "what did they write to me" or "what is going on in that channel". list_message_targets gives you the channel_id and says how many messages are unread.

Reading does not mark anything as read: the unread counter belongs to the member record and only the user's own client clears it.

Args: channel_id: the Discuss channel, from list_message_targets. limit: how many recent messages to return.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNo
channel_idYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden. It discloses that messages are returned newest first, that reading does not mark as read, and explains the unread counter behavior. It does not mention authentication requirements or rate limits, but the core read behavior is transparent. The presence of an output schema compensates for the lack of return format details.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is brief and well-structured: a clear purpose statement, usage examples, a prerequisite link, a behavioral note, and parameter definitions. Every sentence adds value, and there is no redundancy or fluff.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple read operation with two parameters and an output schema, the description covers purpose, usage, parameter semantics, and a key behavioral nuance (unread marking). It does not mention error handling or rate limits, but these are not critical for a straightforward read tool, and the output schema fills the return format gap.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema has 0% description coverage, but the description adds meaning by explaining that channel_id comes from list_message_targets and that limit controls how many recent messages are returned. This provides essential context beyond the schema's type and default, making the parameters understandable.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool reads Discuss conversations, gives concrete examples of when to use it (e.g., 'what did they write to me'), and explicitly distinguishes from the sibling tool 'list_message_targets' by explaining that the latter provides the channel_id and unread count. This leaves no ambiguity about the tool's purpose.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explains when to use the tool (to answer questions about conversation content) and provides a prerequisite ('list_message_targets gives you the channel_id'). It also notes that reading does not mark as read, which is important for usage context. However, it does not explicitly state when not to use it or compare to alternatives like send_channel_message, though the differentiation is implied.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

read_recordA

Read one record by id, always with named fields (writing.md pattern 12).

Omitting fields asks for a short list of state fields — never for all of them: that read is slow at best and fails at worst.

account.move and account.move.line are refused here, because the structural guard wants a move_type filter and this tool has nowhere to put one. Use search_read with [["id", "=", <id>], ["move_type", "=", "out_invoice"]] instead.

And never add up amount_total across records — it is in the record's own currency. amount_total_signed is the company-currency twin to sum.

Args: model: Odoo model, e.g. "sale.order". record_id: The record's database id. fields: Field names to read. Omit for the usual state fields.

ParametersJSON Schema
NameRequiredDescriptionDefault
modelYes
fieldsNo
record_idYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description fully owns behavioral disclosure. It reveals that omitting fields returns a short state list, that reading all fields can be slow or fail, that specific models are refused, and that amount_total is in the record's currency while amount_total_signed is the company-currency sum. These are non-obvious behaviors that prevent misuse.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is dense but every sentence adds value: purpose, constraints, alternative usage, and a currency warning. It is structured with paragraphs and bolded warnings, front-loading the core purpose.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Considering the 3 parameters, the output schema, and 18 sibling tools, the description covers all necessary context: when to use, when to avoid, parameter semantics, and gotchas. The output schema documents return values, so no further explanation is needed there.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, but the description compensates with thorough parameter explanations: model gets an example, record_id is defined, and fields is explained with its default behavior and constraints. This goes beyond the schema's bare type definitions.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with 'Read one record by id' — a specific verb and resource — and distinguishes itself from search_read by noting it reads a single record by ID. It also adds the 'named fields' pattern, clarifying the output format.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicit guidance on when to use this tool vs alternatives: it states that account.move and account.move.line are refused and directs the agent to use search_read with a specific domain. It also warns against requesting all fields and explains the safe default when fields is omitted.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

required_fieldsA

List the fields Odoo demands before it will accept a create, with the default it would apply and how existing records actually use it.

Ask this BEFORE create_record on a model you have not written to in this session. The answer is read from the live instance — fields_get plus default_get — never from a table in this file, so a model customised in-house reports its own requirements.

The dangerous required field is the one that already carries a default: the create succeeds without you naming it and the record lands wherever the default points, with no error to notice. crm.lead.type is the standing example — Odoo defaults it to 'lead', and on an instance that works its pipeline as opportunities that record goes straight to a menu nobody opens. That is why the live distribution is printed beside each default.

Args: model: Odoo model, e.g. "crm.lead".

ParametersJSON Schema
NameRequiredDescriptionDefault
modelYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description fully discloses behavior: it reads from live instance via fields_get/default_get, not from a table. Warns about hidden side effects of defaults. Transparent about data source and output content.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is relatively long but well-structured: purpose first, then usage, then warning example, then parameter. Every sentence adds value, though some could be tightened slightly without losing context.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity and the presence of an output schema, the description covers purpose, usage, behavioral details, and parameter. No critical gaps remain; it provides sufficient context for an agent to use it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0% (no parameter description in schema). The description compensates by explaining the 'model' parameter with an example ('crm.lead') and context about Odoo models, adding meaning beyond the raw schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool lists required fields for a create operation, including defaults and usage distribution. It uses specific verbs ('List', 'demands') and distinguishes itself from siblings like create_record by emphasizing it as a pre-check.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly instructs to ask this tool BEFORE create_record for unfamiliar models. Explains the rationale with a concrete example of dangerous defaults, providing clear when-to-use guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

run_actionA
Destructive

Run a workflow method and report the state it left behind.

The level follows method: confirming or posting is a state change, cancelling or unlinking is destructive and refused unless the server's ceiling was raised deliberately.

Two behaviours come from the Writer and are worth knowing: a returned dict carrying res_model is a wizard to follow rather than a result, and a transition is one-way — calling it twice raises instead of doing nothing.

ParametersJSON Schema
NameRequiredDescriptionDefault
modelYes
methodYes
record_idsYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A3.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description goes well beyond the annotations, which indicate destructiveHint=true and non-idempotent. It explains specific behaviors: a returned dict with 'res_model' indicates a wizard to follow, and transitions are one-way (calling twice raises error). This provides valuable context that annotations alone do not cover, fully justifying the tool's behavior.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is moderately concise but could be more front-loaded. The first sentence clearly states the main purpose, but the subsequent sentences about behavior become complex and may require rereading. Some information, like the one-way transition detail, is important but could be structured more clearly.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool has 3 required parameters, an output schema, and annotations, the description provides sufficient behavioral detail (wizard handling, transition idempotency). It lacks explicit mention of what the output contains, but since an output schema exists, that burden is partially lifted. The description is adequate for an agent to understand key caveats.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0%, and the description does not explicitly describe each parameter. However, the description mentions the 'method' parameter in context ('the level follows method') and implies that 'record_ids' and 'model' are inputs. Although not detailed individually, the description adds enough context about how parameters relate to the tool's behavior, compensating for the lack of schema documentation.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose3/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states that the tool runs a workflow method and reports the state it left behind, which gives a general idea. However, it does not specify what kind of workflow or method (e.g., from which framework or platform), and it does not distinguish itself from siblings like 'cancel_record' or 'write_record' which also deal with state changes.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides some guidance on when the tool is appropriate (e.g., confirming/posting as state changes) and when it is destructive (cancelling/unlinking, raised ceiling). It also mentions a one-way transition behavior. However, it does not explicitly state when to use this tool over siblings such as 'write_record' or 'cancel_record', nor does it list alternatives.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

search_readA

Search and read records in one call (Odoo search_read).

Two pitfalls this tool cannot fix for you:

  • account.move and account.move.line mix customer invoices, vendor bills, credit notes and raw journal entries. A domain without move_type is refused — add ["move_type", "=", "out_invoice"] (or in_invoice, out_refund, in_refund) so the answer matches what the user sees on screen.

  • NEVER sum amount_total: it is expressed in each record's own currency, and eight foreign-currency invoices once inflated a total 11,9×. Ask for amount_total_signed instead — any field with a _signed twin is stored in company currency, and the twin is the one to add up.

Args: model: Odoo model, e.g. "sale.order". domain: Odoo domain, e.g. [["state", "=", "sale"]]. fields: Field names to return. Name them: the default asks for every field, which is slow and can fail to serialise on wide models. limit: Rows to return. Hard-capped at 200. offset: Rows to skip — how to page past a truncated result. company_ids: Companies to read from, e.g. [1, 2]. On a multi-company instance, omitting this reports one company as the whole business.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNo
modelYes
domainYes
fieldsNo
offsetNo
company_idsNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations were provided, yet the description transparently discloses multiple behavioral details: hard-capped limit at 200, multi-company reporting bias, performance warning about requesting all fields, and the currency conversion pitfall. This fully compensates for the missing annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Description is front-loaded with the core purpose, then structured into two numbered pitfalls, then parameter explanations. Every sentence adds value—no filler. Slight length but justified given the complexity of Odoo's quirks. A minor point: the parameter list could be slightly more compact, but the trade-off for clarity is acceptable.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With 6 parameters, 0% schema coverage, no annotations, yet an output schema exists, the description covers parameter semantics, pitfalls, return behavior (hard cap, paging), and domain-specific business logic. It is completely sufficient for an AI agent to execute this tool safely and effectively, including handling complex edge cases.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, but the description explains every parameter (model, domain, fields, limit, offset, company_ids) with usage examples, default behaviors, and warnings. It adds substantial meaning beyond what the schema types alone communicate, e.g., explaining the domain format, performance cost of null fields, and the company_ids multi-company trap.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Description uses specific verb 'Search and read' with resource 'records in one call' and immediately references the Odoo method 'search_read'. It clearly distinguishes from siblings like 'read_record' (probably single-record read) and 'count_records' by explaining this is a combined search-and-read operation returning fields.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides two explicit, high-value pitfalls with concrete examples: mandatory 'move_type' for account moves, and never summing 'amount_total' (use '_signed' twin). This tells the agent when NOT to use certain patterns and what alternatives to use, which is exceptional guidance beyond basic tool selection.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

send_channel_messageA

Post to an EXISTING Discuss channel — everyone in it sees this.

The channel is never created here: list_message_targets shows the ones that exist, and posting to a room of the wrong size is not recoverable by deleting the message afterwards.

Members who are not employees of this instance — portal users, guests — are named in a refusal rather than written to, the same rule notify_user applies to external followers. Nothing is posted in that case.

Args: channel_id: from list_message_targets. message: the body, plain text or simple HTML.

ParametersJSON Schema
NameRequiredDescriptionDefault
messageYes
channel_idYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Without annotations, the description fully bears the burden of behavioral disclosure. It explains the side effect (everyone in channel sees it), the failure mode (non-employee members cause refusal, no post), and the irreversibility (deleting the message does not help). This is comprehensive for a simple mutation tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-structured with a brief opening, key warnings in separate sentences, and an Args section. Slightly verbose in the middle paragraph, but each sentence adds clear value. Could potentially trim the middle block slightly, but overall efficient.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the simple input schema (2 string params), no annotations, but an output schema present (which can describe return values), the description covers all critical behavior: side effects, prerequisites, error conditions, and parameter semantics. Nothing essential is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema has 0% description coverage, so the description must compensate entirely. It explains that `channel_id` must come from `list_message_targets`, and `message` accepts plain text or simple HTML. This adds crucial meaning beyond the bare property names 'channel_id' and 'message'.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool posts to an existing Discuss channel, distinguishes it from creating a channel, and indicates the audience. The verb 'post' and resource 'existing Discuss channel' are specific and unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly tells the agent not to use this to create channels, directs to `list_message_targets` for valid channel IDs, and warns about unrecoverability of wrong-sized room posts. It also references sibling `notify_user` for external follower rules, providing clear when-to-use and when-not-to-use guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

send_direct_messageA

Send a 1-to-1 Discuss message that appears in the user's chat systray.

This is the tool for "tell X", "message X", "warn X". It opens the private chat with that user — reusing the existing one, channel_get matches on the exact pair — and posts there. The bus pushes it in real time and it persists, so a recipient who is offline finds it on their next login.

It reaches them whatever their notification setting says, and sends no email at all. That is the difference from notify_user, which follows the recipient's preference and lands in the Inbox bell instead.

Args: user_id: res.users id of the recipient — from list_message_targets. message: the body, plain text or simple HTML.

ParametersJSON Schema
NameRequiredDescriptionDefault
messageYes
user_idYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.8/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden of behavioral disclosure. It explains that the message opens a private chat (reusing existing), is pushed in real time, persists, and reaches offline users on next login. It also notes that it bypasses notification settings and sends no email. Missing are details about permissions, error handling, or response format, but the core behavior is well-covered.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-structured: a brief one-sentence summary, followed by use-case context, behavioral details, a clear distinction from a sibling, and then parameter descriptions. Every sentence adds value, and it is appropriately sized for a two-parameter tool.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given that the tool has only two parameters, no annotations, and an existing output schema, the description covers purpose, usage, behavioral details, parameter semantics, and distinction from siblings. It does not need to explain return values since the output schema is present. The description is sufficiently complete for an agent to select and invoke the tool correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema has 0% description coverage, so the description must compensate. It explains that user_id is the 'res.users id of the recipient — from list_message_targets', adding a source for valid IDs. It describes message as 'plain text or simple HTML', providing format guidance. Both parameters are clearly explained beyond the schema types.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool sends a 1-to-1 Discuss message appearing in the user's chat systray. It uses specific verbs 'send' and 'message', identifies the resource as a direct message, and distinguishes it from sibling tools like notify_user and send_channel_message by explaining the exact behavior.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly contrasts with notify_user, stating that send_direct_message reaches the recipient regardless of notification settings and sends no email, whereas notify_user follows preferences and lands in the Inbox bell. It also provides typical use cases ("tell X", "message X", "warn X") and explains that it reuses existing private chats, giving clear guidance on when to use this tool.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

write_recordA
DestructiveIdempotent

Write field values to one record and report what actually changed.

Writing the value a record already holds succeeds and changes nothing; only the before/after comparison tells that apart from a real update, so that comparison is the answer.

Setting active to False archives the record — the same visible outcome as deleting it — and is classified destructive rather than as a plain write.

ParametersJSON Schema
NameRequiredDescriptionDefault
modelYes
valuesYes
record_idYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description goes far beyond the annotations by explaining the idempotent behavior (writing same value succeeds but changes nothing), the destructive nature of setting active=False (archives/deletes), and that the tool reports before/after comparisons. It provides concrete behavioral context that the annotations (readOnlyHint=false, idempotentHint=true, destructiveHint=true) only hint at.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is efficiently structured in three paragraphs: the first states the core purpose, the second explains an edge case (idempotency), and the third warns about destructive behavior. While almost every sentence adds value, it could be slightly more compact by merging the first two sentences into a single line. Overall, it is well-organized and focused.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool has an output schema (which presumably documents the return format), the description adequately covers all critical aspects: what it does, idempotency, destructive side effects, and change reporting. It is complete for a write tool that only requires model, record_id, and values. No missing information is detected.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0%, so the description fully carries the burden. It explains how the 'values' parameter behaves (setting active=False is destructive) and that the report shows before/after. However, it doesn't explicitly describe the 'model' and 'record_id' parameters beyond what is in the schema, though the overall usage is clear from context.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses the specific verb 'Write' with the resource 'one record' and explicitly distinguishes the tool by stating it reports what actually changed. It clearly differentiates from siblings like 'create_record' (which creates new records) and 'read_record' (which only reads).

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly explains when to use this tool (to write field values and see actual changes) and when it is not a real update (idempotency case). It also provides a key guideline: setting 'active' to False archives the record and is classified as destructive, which helps the agent avoid unintended destructive actions.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 19 tool updatesv0.1.1
    • First observedcancel_record
    • First observedcount_records
    • First observedcreate_activity
    • First observedcreate_record
    • First observeddownload_docs
    • First observedexplore_module
    • First observedgenerate_pdf
    • First observedinstance_overview
    • First observedlist_known_modules
    • First observedlist_message_targets
    • First observednotify_user
    • First observedread_conversation
    • First observedread_record
    • First observedrequired_fields
    • First observedrun_action
    • First observedsearch_read
    • First observedsend_channel_message
    • First observedsend_direct_message
    • First observedwrite_record

TDQS

A3.7/5.0

Scored across 19 tools

Disambiguation5/5

Each tool targets a distinct Odoo operation: reading, searching, counting, creating, writing, workflow actions, messaging, module exploration, etc. While messaging has multiple tools (notify_user, send_direct_message, send_channel_message), their descriptions clearly differentiate by context (record chatter, 1-to-1 chat, channel). No overlapping purposes remain ambiguous.

Naming Consistency5/5

All tools follow a consistent verb_noun pattern in snake_case (e.g., search_read, create_record, list_message_targets). The naming is predictable and intuitive, with verbs like read, create, write, send, list, and explore clearly indicating the action.

Tool Count4/5

With 19 tools, the server covers a broad set of Odoo capabilities (CRUD, workflow, messaging, file handling, module introspection). While slightly above the typical 3-15 recommended range, the count is justified by the complexity of the ERP domain and each tool serves a distinct purpose without redundancy.

Completeness4/5

The tool surface covers essential CRUD operations, workflow actions, messaging, document handling, and instance/ module exploration. However, there is no dedicated delete tool (only cancel for specific workflows) and no bulk update or file upload tool. These minor gaps are workable but prevent full lifecycle coverage.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    B
    quality
    D
    maintenance
    An MCP server that enables AI assistants to interact with Odoo ERP apps like Inventory, CRM, Sales, and Manufacturing. It allows users to read, create, and manage Odoo records and workflows using natural language commands.
    25
    17 npm
    1
    ISC
  • A
    license
    Not graded
    quality
    D
    maintenance
    An extensible MCP server that integrates Odoo with LLMs to enable querying and managing business data like partners, quotations, and sales orders. It supports custom tool registration and multiple transport protocols for both local and remote communication.
    2
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    An MCP server that connects AI assistants to Odoo ERP instances via the built-in XML-RPC API without requiring any additional addons. It enables users to search, create, update, and manage Odoo records and models through natural language.
    27 npm
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    An MCP server that enables AI assistants to interact with Odoo ERP, allowing natural language queries, record creation, updates, and deletions.
    LGPL 3.0