ams-odoo-mcp-connector
Provides read access to Odoo business data (search/read records, list installed modules) and enables creating records with a human-approval gate, respecting strict allowlists.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@ams-odoo-mcp-connectorFind 3 sales orders with their customer names."
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
AMS Odoo MCP Connector
Python MCP (Model Context Protocol) server that gives an AI assistant (such as Claude) access to an Odoo instance: read business data and -only with human approval- create records. It is a standalone intermediary service (not a module inside Odoo) and instance-agnostic: it works against any Odoo 18/19 by changing only configuration.
Each person runs their own copy with their own Odoo credentials. No credentials travel in this repository.
For business context and design principles, see CLAUDE.md.
1. Requirements
Python 3.11+ (tested on 3.13)
git
An Odoo 18/19 instance reachable from your machine and an API user (starting with read-only permissions is ideal).
Optional: Docker (for the containerized connection checks).
Related MCP server: Odoo MCP Server
2. Quickstart
git clone <REPO-URL> ams-odoo-mcp-connector
cd ams-odoo-mcp-connectorCreate the virtual environment and install the package:
Windows (PowerShell)
python -m venv .venv
.\.venv\Scripts\Activate.ps1
pip install -e ".[dev]"macOS / Linux
python3 -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"3. Configure your credentials
Copy the template and edit it with your Odoo details:
cp .env.example .envVariable | Required | Description |
| yes | Base URL of your Odoo instance. |
| yes | Database name. |
| yes | API user. |
| yes | Password / API key. |
| for writes | Secret that signs the approval gate. Without it, record creation is disabled. |
| no | Pins the major version (e.g. |
| no | Directory for the allowlists (defaults to |
| no | Log level (to stderr). |
Generate your own ODOO_MCP_APPROVAL_SECRET (required to create records):
python -c "import secrets; print(secrets.token_urlsafe(48))"The
.envis git-ignored: it is yours and local. Never commit it.
4. Verify that everything loads
ams-odoo-mcp-config # prints your config with secrets maskedIf you have connectivity to Odoo, run the read-only connection check:
python smoke_test.py # login + version + a harmless search_read. Writes NOTHING.Expected success output: OK Handshake correct.
5. Connect it to Claude
The assistant launches the server as a local process (stdio). It carries no credentials:
the server reads your .env on its own.
Claude Desktop
Edit the configuration file:
Windows:
%APPDATA%\Claude\claude_desktop_config.json(in the Microsoft Store version, the real path is under...\Packages\Claude_*\LocalCache\Roaming\Claude\claude_desktop_config.json)macOS:
~/Library/Application Support/Claude/claude_desktop_config.json
Add (or merge) this block, with your paths:
{
"mcpServers": {
"ams-odoo": {
"command": "RUTA-A-TU/.venv/Scripts/python.exe",
"args": ["-m", "odoo_mcp.server"],
"cwd": "RUTA-ABSOLUTA-A-ESTE-REPO"
}
}
}(on macOS/Linux the command is RUTA-A-TU/.venv/bin/python.)
Quit Claude Desktop completely (tray icon -> Quit) and reopen it.
Claude Code
cp .mcp.json.example .mcp.jsonEdit .mcp.json with the path to your venv Python and to this repo. When you open the
project, Claude Code will ask you to approve the server.
6. Try it
In a Claude chat, ask for example:
"List the modules installed in Odoo." -> uses
odoo_list_modules."Find 3 sales orders with their customer." -> uses
odoo_search_read."Schedule an installation." ->
odoo_create_recordwill return a proposal for you to approve; nothing is created until you confirm.
The three tools
Tool | What it does | Type |
| Reads records from an allowed model, with bounded pagination. | Read |
| Lists the modules installed in the instance. | Read |
| Creates a record after human approval (two-phase gate). | Write |
Write gate: the first call (without approval_token) returns a
PROPOSAL with a signed token and creates nothing; the second, with that token
approved by a human, is the only one that executes the create. The token is signed
(it cannot be forged), bound to the exact values, and expires in 5 minutes.
Governance and security
Strict allowlists in
config/: only the listed models can be read/created. The write list starts scoped tocalendar.event.Human-in-the-loop for all writes (gate + signed token).
Secrets only in configuration (never in code, logs, or Docker image).
Never assume: if it cannot confirm something in Odoo, it says so; a permissions problem is never reported as "the data does not exist".
Architecture (odoo_mcp package, in src/)
Module | Responsibility |
| Typed config from environment/ |
| Stateless JSON-RPC transport, authentication, re-login, safe connection backoff. |
| High-level |
| Instance version and installed modules; availability of a model. |
| Allowlists, field validation, pagination cap, availability cache. |
| Error hierarchy + |
| HMAC token for the write gate (propose->commit). |
| Logic of the 3 tools (independent of the MCP runtime). |
| MCP wiring (stdio), lifespan, tool registration. |
Development
pytest # 68 tests (use mocks; no Odoo required)
ruff check src tests # lintContainerized connection checks (Docker, hardened)
Credentials are injected from your .env; they do not live in the image. The container
runs non-root, read-only rootfs, no capabilities, no privilege escalation.
docker compose build smoke
docker compose run --rm smoke # read-only: login + version + search_read
docker compose run --rm smoke python write_test.py # controlled write: create -> verify -> deleteTroubleshooting
Symptom | Likely cause / fix |
| The |
| Incorrect |
| Network/VPN/firewall/URL: the instance is not reachable from your machine. |
Claude Desktop shows "failed" | Check the |
Creation says "disabled" |
|
(c) 2026 onePhase - Proprietary. See LICENSE.
Available Tools
3 toolsodoo_create_recordA
Create a record in an Odoo model allowed for writing, ONLY after human approval. Call WITHOUT 'approval_token': returns a PROPOSAL (preview + token) and creates nothing. To execute, a human resends the same call with the same 'model'/'values' and the received 'approval_token'.
| Name | Required | Description | Default |
|---|---|---|---|
| model | Yes | ||
| values | Yes | ||
| approval_token | No |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description reveals the non-obvious two-step behavior where the first call returns a proposal without creating anything, and execution only occurs on the second call with the token. This adds critical context beyond the annotations' simple mutation flag, and there is no contradiction with the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is three sentences, each serving a purpose: statement of function, explanation of the first step, and explanation of the execution step. It is concise with no redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the complexity of the human-approval flow, the description fully explains the protocol: what the first call returns, and what the second call requires. The presence of an output schema likely covers proposal details, so the description is complete for selection and invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The description adds essential semantics for the 'approval_token' parameter, explaining its role in the two-step flow and requiring identical 'model'/'values' for execution. While 'model' and 'values' are not deeply elaborated, the token lifecycle is fully clarified, compensating for the 0% schema description coverage.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool creates a record in an Odoo model, and specifies it is for write operations with human approval. This distinguishes it from sibling read/list tools by explicitly naming the write action and the approval requirement.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides explicit usage guidance: call without 'approval_token' to obtain a proposal, then have a human resend with the token to execute. It also specifies that the model must be 'allowed for writing', giving a clear precondition for use.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
odoo_list_modulesARead-only
List the modules installed on the Odoo instance (name, description, version).
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The annotations already declare readOnlyHint=true and destructiveHint=false, covering the safety profile. The description adds the returned fields (name, description, version) but no additional behavioral context such as ordering, pagination, authorization requirements, or potential performance implications. This is acceptable but not rich.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single, well-structured sentence that front-loads the action and resource, with no filler or redundant wording. It is appropriately concise for the tool's simplicity.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
This is a simple, parameterless read-only tool with strong annotations and an output schema present. The description provides the core return information (installed modules with name, description, version), which is complete for this level of complexity.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema is empty (0 parameters), so there are no parameter semantics to explain. The description does not need to compensate for missing schema coverage, and with zero params the baseline score is 4.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb ('List') and identifies the resource ('modules installed on the Odoo instance'), and even lists the returned fields. This makes the tool's purpose unmistakable and clearly distinct from siblings like odoo_search_read and odoo_create_record.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The tool's purpose is self-evident from the description and nameāuse it when you need to enumerate installed Odoo modules. While no explicit alternatives are mentioned, the context is clear and there are no exclusions or special conditions. The lack of explicit sibling differentiation is minor because the intent is obvious.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
odoo_search_readARead-only
Read records from an allowed Odoo model. 'domain' is an Odoo search domain (list of conditions); 'fields' limits the columns; 'limit'/'offset' paginate (the limit is bounded to the configured maximum).
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | ||
| model | Yes | ||
| domain | No | ||
| fields | No | ||
| offset | No |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already indicate readOnly, openWorld, and non-destructive behavior. The description adds useful constraints: the model must be 'allowed' and the limit is bounded to a configured maximum. These go beyond the annotation defaults, providing context about system-imposed boundaries.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two concise sentences: the first states the purpose, the second explains parameter semantics. No wasted words, all information is relevant and efficiently front-loaded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the output schema exists, return values are documented externally. The description covers purpose, parameter meanings, and key constraints (allowed model, bounded limit). It lacks details on optionality (e.g., domain default) and error behavior, but for a read operation with good annotations, this is reasonably complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
With 0% schema description coverage, the description compensates by explaining the meaning of 'domain' (Odoo search domain list), 'fields' (limits columns), and 'limit'/'offset' (pagination). The 'model' parameter is implied as the target of the read. This covers most parameters meaningfully, though 'model' lacks explicit detail.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool reads records from an Odoo model, using the specific verb 'read' and naming the resource. It distinguishes itself from siblings: 'odoo_list_modules' lists modules, 'odoo_create_record' creates records, while this tool reads existing records.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides clear context by explaining the parameters and noting the 'allowed' model restriction and bounded limit. It does not explicitly state when to use this tool over alternatives, but the read-only purpose is clear and it lacks exclusion criteria. A 4 is appropriate for clear context without explicit alternatives.
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.
3 tool updates
v0.1.0- First observed
odoo_create_record - First observed
odoo_list_modules - First observed
odoo_search_read
TDQS
Scored across 3 tools
Each tool targets a distinct operation: reading records, listing modules, and creating records with an approval flow. There is no overlap in purpose or ambiguous boundaries between them.
All tool names follow the consistent pattern 'odoo_' + verb_noun (search_read, list_modules, create_record). The naming is uniform and predictable, despite mixing verbs like 'search' and 'list'.
With only 3 tools, the server is on the lean side but still within a reasonable range for a focused connector. Each tool provides a distinct function, though the count is minimal.
The tool surface lacks essential CRUD operations such as update and delete, which are common in Odoo data access. While read and create are covered, missing write operations and additional search capabilities create significant gaps for a general-purpose connector.
Maintenance
Related MCP Connectors
MCP server unifying ERPs, CRMs, APIs and knowledge base for Claude, ChatGPT and Gemini.
The HubSpot MCP Server acts as a bridge that enables AI assistants and Large Language Models to securely interact with HubSpot CRM data through natural conversation, without requiring users to understand complex API structures. It provides read-only access to standard CRM objects (contacts, companies, deals, tickets, products, invoices, and more) and their associations, secured via OAuth 2.0, allowing AI agents to perform tasks like summarizing deals, fetching company updates, and looking up record changes.
- ZapierOAuthcom.zapier
Hosted MCP server connecting AI assistants to 9,000+ apps and 40,000+ actions via Zapier.
MCP server that lets AI assistants use all OneSchema features exposed via the public API.
Related MCP Servers
- AlicenseNot gradedqualityAmaintenanceAn MCP server that enables AI assistants like Claude to interact with Odoo ERP systems through natural language, allowing users to search, create, update, and manage business data in their Odoo instance.1,571 PyPI385Mozilla Public 2.0
- AlicenseBqualityDmaintenanceAn 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.2511 npm1ISC
- AlicenseNot gradedqualityDmaintenanceAn 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.25 npmMIT
- AlicenseNot gradedqualityCmaintenanceAn MCP server that enables AI assistants to interact with Odoo ERP, allowing natural language queries, record creation, updates, and deletions.LGPL 3.0