Skip to main content
Glama
nestordiaz-one

ams-odoo-mcp-connector

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-connector

Create 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 .env

Variable

Required

Description

ODOO_URL

yes

Base URL of your Odoo instance.

ODOO_DB

yes

Database name.

ODOO_USER

yes

API user.

ODOO_PASSWORD

yes

Password / API key.

ODOO_MCP_APPROVAL_SECRET

for writes

Secret that signs the approval gate. Without it, record creation is disabled.

ODOO_VERSION_OVERRIDE

no

Pins the major version (e.g. 18) and skips autodetection.

ODOO_MCP_CONFIG_DIR

no

Directory for the allowlists (defaults to config).

ODOO_MCP_LOG_LEVEL

no

Log level (to stderr). INFO by default.

Generate your own ODOO_MCP_APPROVAL_SECRET (required to create records):

python -c "import secrets; print(secrets.token_urlsafe(48))"

The .env is git-ignored: it is yours and local. Never commit it.


4. Verify that everything loads

ams-odoo-mcp-config        # prints your config with secrets masked

If 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.json

Edit .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_record will return a proposal for you to approve; nothing is created until you confirm.


The three tools

Tool

What it does

Type

odoo_search_read(model, domain?, fields?, limit?, offset?)

Reads records from an allowed model, with bounded pagination.

Read

odoo_list_modules()

Lists the modules installed in the instance.

Read

odoo_create_record(model, values, approval_token?)

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 to calendar.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

config.py

Typed config from environment/.env with fail-fast; finds .env and config/ without relying on the cwd.

session_manager.py

Stateless JSON-RPC transport, authentication, re-login, safe connection backoff.

odoo_client.py

High-level execute_kw with re-login -> retry cycle.

discovery.py

Instance version and installed modules; availability of a model.

governance.py

Allowlists, field validation, pagination cap, availability cache.

errors.py

Error hierarchy + translate() to actionable natural language.

approval.py

HMAC token for the write gate (propose->commit).

tools.py

Logic of the 3 tools (independent of the MCP runtime).

server.py

MCP wiring (stdio), lifespan, tool registration.


Development

pytest                    # 68 tests (use mocks; no Odoo required)
ruff check src tests      # lint

Containerized 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 -> delete

Troubleshooting

Symptom

Likely cause / fix

Missing required configuration variables

The .env is missing or wrong. Check with ams-odoo-mcp-config.

Odoo rejected the credentials

Incorrect ODOO_USER / ODOO_PASSWORD / ODOO_DB, or no login permission.

Could not communicate with the Odoo instance

Network/VPN/firewall/URL: the instance is not reachable from your machine.

Claude Desktop shows "failed"

Check the command/cwd path in the JSON and fully restart Desktop. Logs: %APPDATA%\Claude\logs\mcp-server-ams-odoo.log.

Creation says "disabled"

ODOO_MCP_APPROVAL_SECRET is missing from your .env.


(c) 2026 onePhase - Proprietary. See LICENSE.

Available Tools

3 tools
odoo_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'.

ParametersJSON Schema
NameRequiredDescriptionDefault
modelYes
valuesYes
approval_tokenNo

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.9/5.0
Behavior5/5

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.

Conciseness5/5

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.

Completeness5/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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_modulesA
Read-only

List the modules installed on the Odoo instance (name, description, version).

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.3/5.0
Behavior3/5

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.

Conciseness5/5

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.

Completeness5/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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_readA
Read-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).

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNo
modelYes
domainNo
fieldsNo
offsetNo

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.4/5.0
Behavior4/5

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.

Conciseness5/5

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.

Completeness4/5

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.

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 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.

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 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.

Usage Guidelines4/5

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.

  1. 3 tool updatesv0.1.0
    • First observedodoo_create_record
    • First observedodoo_list_modules
    • First observedodoo_search_read

TDQS

A4.3/5.0

Scored across 3 tools

Disambiguation5/5

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.

Naming Consistency5/5

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'.

Tool Count4/5

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.

Completeness2/5

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

ActivityMaintained
ResponsivenessSyncing

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    A
    maintenance
    An 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 PyPI
    385
    Mozilla Public 2.0
  • 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
    11 npm
    1
    ISC
  • 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.
    25 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