odoo19-mcp-server
Odoo 19 MCP 서버 (JSON-2 API)
Odoo 19 MCP 서버, JSON-2 API를 사용하여 연결합니다.
본 프로젝트는 Odoo 19 JSON-2 API 전체 사용 가이드를 기반으로 개발되었습니다.

기술 스택
Python: 3.13
FastMCP: >=3.0.0,<4.0.0
odoo-client-lib: 2.0.1 (JSON-2 API)
Related MCP server: odxproxy-mcpserver
아키텍처
flowchart TB
subgraph Client["MCP Client"]
CC[Claude Code]
GC[Gemini CLI]
MI[MCP Inspector]
end
subgraph Server["MCP Server (FastMCP)"]
R[Resources<br/>odoo://models<br/>odoo://user<br/>odoo://company]
T[Tools<br/>search_records<br/>create_record<br/>update_record]
DI[Dependency Injection<br/>get_shared_client]
end
subgraph RPC["OdooJsonRpcClient"]
OL[odoolib<br/>json2/json2s protocol]
end
subgraph Odoo["Odoo Server"]
EP["/jsonrpc endpoint"]
end
Client -->|MCP Protocol<br/>stdio/http/sse| Server
R --> DI
T --> DI
DI --> RPC
RPC -->|HTTP/HTTPS| OdooMCP 핵심 개념
리소스(Resources) vs 도구(Tools)
특성 | 리소스 (Resources) | 도구 (Tools) |
용도 | 컨텍스트 정보 제공 | 작업/동작 수행 |
트리거 | 클라이언트 제어 (예: Claude Code) | LLM이 호출 여부 자동 결정 |
매개변수 | 없음 (또는 URI 매개변수) | 있음 (LLM이 생성해야 함) |
비유 | 직원 핸드북 (배경 지식) | 도구 상자 (필요 시 사용) |
HTTP 비유 | GET (읽기) | POST/PUT/DELETE (작업) |
리소스 - 동적 컨텍스트, LLM이 처음에 알고 있는 배경 정보:
odoo://user → "我是誰"
odoo://company → "我在哪間公司"
odoo://models → "有哪些模型可用"도구 - 필요할 때만 호출하는 작업:
search_records(model="res.partner", domain=[...]) → 搜尋
create_record(model="sale.order", values={...}) → 建立왜 기본 프롬프트(Default Prompt)를 사용하지 않나요?
방식 | 기본 프롬프트 | 리소스 |
데이터 소스 | 코드에 하드코딩 | Odoo에서 실시간 조회 |
업데이트 시점 | 배포 시 | 연결할 때마다 |
사용자 변경 시 | 정보 오류 | 자동으로 정확함 |
# ❌ Default Prompt(寫死)
SYSTEM_PROMPT = "當前用戶: Admin" # 換人登入就錯了
# ✅ Resource(動態)
@mcp.resource("odoo://user")
def get_current_user():
return client.read("res.users", [uid]) # 即時查詢결론: 리소스는 정적 텍스트가 아닌 "동적 컨텍스트"입니다.
참고: MCP Resources | MCP Tools
환경 변수
변수 | 설명 | 기본값 |
| Odoo 서버 URL |
|
| 데이터베이스 이름 | - |
| API Key 인증 | - |
| 읽기 전용 모드 (쓰기 작업 금지) |
|
.env 파일 생성:
cp .env.example .env설치
pip install -r requirements.txt실행 방법
개발 모드 (MCP Inspector)
fastmcp dev inspector odoo_mcp_server.py전송 모드 (Transport)
본 프로젝트는 세 가지 MCP 전송 모드를 지원합니다:
모드 | 설명 | 적용 상황 |
| 표준 입출력 (기본값) | Claude Desktop, Cursor IDE, 로컬 개발 |
| HTTP 프로토콜 | 원격 서비스, n8n, 웹 애플리케이션 통합 |
| Server-Sent Events (사용 중단 예정) | 이전 버전 클라이언트와의 하위 호환성 |
stdio vs HTTP/SSE: 연산 위치
두 모드의 핵심 차이는 "누가 MCP 서버를 시작하는가"와 "연산이 어디서 수행되는가"입니다:
stdio 모드 (로컬 연산)
┌─────────────────────────────────────┐
│ 你的電腦 💻 │
│ │
│ Claude Desktop ──> MCP Server │
│ (使用本機算力) │
└─────────────────────────────────────┘클라이언트(예: Claude Desktop)가 MCP 서버를 자식 프로세스로 시작
MCP 서버가 내 컴퓨터의 CPU/RAM을 사용
클라이언트 시작/종료와 함께 서버도 시작/종료
HTTP/SSE 모드 (원격 연산)
┌──────────────┐ ┌──────────────────┐
│ 你的電腦 │ │ 雲端 ☁️ │
│ │ │ │
│Claude Desktop│ ──網路──>│ MCP Server │
│ (輕量) │ │ (使用雲端算力) │
└──────────────┘ └──────────────────┘MCP 서버가 클라우드/원격 호스트에서 독립적으로 실행
여러 클라이언트가 동시에 동일한 서버에 연결 가능
팀 공유, n8n 통합, 운영 환경에 적합
모드별 실행
# stdio 模式(預設)
python odoo_mcp_server.py
# HTTP 模式
python odoo_mcp_server.py --transport http --host 0.0.0.0 --port 8000
# SSE 模式(已棄用,建議使用 HTTP)
python odoo_mcp_server.py --transport sse --host 0.0.0.0 --port 8000클라우드 배포 (HTTP 모드)
Docker Compose 예시:
services:
odoo-mcp:
build: .
ports:
- "8000:8000"
environment:
- ODOO_URL=http://odoo:8069
- ODOO_DATABASE=odoo19
- ODOO_API_KEY=your_api_key_here
command: ["python", "odoo_mcp_server.py", "--transport", "http", "--host", "0.0.0.0", "--port", "8000"]
restart: unless-stopped클라이언트 설정(claude)에서 URL 연결 사용:
claude mcp add --transport http odoo-mcp https://your-cloud-server.com:8000/mcp{
"mcpServers": {
"odoo-mcp": {
"type": "http",
"url": "https://your-cloud-server.com:8000/mcp"
}
}
}MCP 리소스
URI | 설명 |
| 모든 모델 나열 |
| 모델 필드 정의 가져오기 |
| 단일 레코드 가져오기 |
| 현재 로그인한 사용자 정보 |
| 현재 사용자의 소속 회사 정보 |
MCP 도구
도구 | 설명 | 읽기 전용 |
| 사용 가능한 모델 나열/검색 | Yes |
| 모델 필드 정의 가져오기 | Yes |
| 레코드 검색 | Yes |
| 레코드 개수 세기 | Yes |
| 지정된 ID의 레코드 읽기 | Yes |
| 레코드 생성 | No |
| 레코드 수정 | No |
| 레코드 삭제 (2차 확인 필요) | No |
| 모델 메서드 실행 | Depends |
Claude Code MCP 설정
설정 파일은 ~/.claude.json에 위치합니다:
로컬 실행
claude mcp add odoo-mcp-server -- python odoo_mcp_server.py{
"mcpServers": {
"odoo-mcp-server": {
"command": "/bin/python",
"args": [
"odoo_mcp_server.py"
]
}
}
}Docker (host.docker.internal)
Odoo가 로컬에서 실행 중인 경우:
claude mcp add odoo-mcp-server -- docker run -i --rm --add-host=host.docker.internal:host-gateway -e ODOO_URL=http://host.docker.internal:8069 -e ODOO_DATABASE=odoo19 -e ODOO_API_KEY=your_api_key_here odoo-mcp-server{
"mcpServers": {
"odoo-mcp-server": {
"command": "docker",
"args": [
"run",
"-i",
"--rm",
"--add-host=host.docker.internal:host-gateway",
"-e",
"ODOO_URL=http://host.docker.internal:8069",
"-e",
"ODOO_DATABASE=odoo19",
"-e",
"ODOO_API_KEY=your_api_key_here",
"odoo-mcp-server"
]
}
}
}Docker (호스트 네트워크)
호스트 네트워크 모드 사용:
claude mcp add odoo-mcp-server -- docker run -i --rm --network host -e ODOO_URL=http://localhost:8069 -e ODOO_DATABASE=odoo19 -e ODOO_API_KEY=your_api_key_here odoo-mcp-server{
"mcpServers": {
"odoo-mcp-server": {
"command": "docker",
"args": [
"run",
"-i",
"--rm",
"--network",
"host",
"-e",
"ODOO_URL=http://localhost:8069",
"-e",
"ODOO_DATABASE=odoo19",
"-e",
"ODOO_API_KEY=your_api_key_here",
"odoo-mcp-server"
]
}
}
}Docker (원격 Odoo)
claude mcp add odoo-mcp-server -- docker run -i --rm -e ODOO_URL=https://example.com/ -e ODOO_DATABASE=odoo19 -e ODOO_API_KEY=your_api_key_here odoo-mcp-server{
"mcpServers": {
"odoo-mcp-server": {
"command": "docker",
"args": [
"run",
"-i",
"--rm",
"-e",
"ODOO_URL=https://example.com/",
"-e",
"ODOO_DATABASE=odoo19",
"-e",
"ODOO_API_KEY=your_api_key_here",
"odoo-mcp-server"
]
}
}
}Docker 빌드
docker build -t odoo-mcp-server .Gemini MCP 설정
gemini mcp add --scope user odoo-mcp docker -- run -i --rm --add-host=host.docker.internal:host-gateway -e ODOO_URL=http://host.docker.internal:8069 -e ODOO_DATABASE=odoo19 -e ODOO_API_KEY=your_api_key_here odoo-mcp-server{
"mcpServers": {
"odoo-mcp": {
"command": "docker",
"args": [
"run",
"-i",
"--rm",
"--add-host=host.docker.internal:host-gateway",
"-e",
"ODOO_URL=http://host.docker.internal:8069",
"-e",
"ODOO_DATABASE=odoo19",
"-e",
"ODOO_API_KEY=your_api_key_here",
"odoo-mcp-server"
]
}
}
}보안 메커니즘
읽기 전용 모드
READONLY_MODE=true를 설정하여 읽기 전용 모드를 활성화합니다. 운영 환경 조회용으로 적합합니다:
쓰기 도구(
create_record,update_record,delete_record,execute_method)는 FastMCP 태그를 통해 직접 숨겨지며, LLM은 이러한 도구를 볼 수 없습니다.
삭제 2차 확인
delete_record는 내장된 확인 메커니즘을 가지고 있습니다. LLM은 먼저 confirm=False로 호출하여 확인 프롬프트를 받아야 하며, 사용자의 동의를 얻은 후 confirm=True로 삭제를 실행해야 합니다.
상태 확인 (Health Check)
HTTP/SSE 전송 모드에서 /health 엔드포인트를 제공합니다:
curl http://localhost:8000/health
# {"status": "healthy", "service": "odoo-mcp-server", "version": "1.0.0"}Docker healthcheck, Kubernetes probe, 로드 밸런서 상태 확인에 적합합니다. stdio 모드에는 영향을 주지 않습니다.
라이선스
Apache 2.0
Available Tools
9 toolscount_recordsARead-onlyIdempotent
Count records in an Odoo model matching the domain.
| Name | Required | Description | Default |
|---|---|---|---|
| model | Yes | Model name (e.g., 'res.partner') | |
| domain | No | Odoo search domain (list of conditions). Examples: - Simple: [["active", "=", True]] - Multiple (AND): [["is_company", "=", True], ["country_id", "=", 1]] - OR condition: ["|", ["type", "=", "contact"], ["type", "=", "invoice"]] - any (Odoo 19+): [["order_line", "any", [["product_uom_qty", ">", 5]]]] - Operators: =, !=, >, >=, <, <=, like, ilike, in, not in, child_of, any |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already indicate readOnlyHint and idempotentHint. Description adds no further behavioral context beyond the count operation.
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?
Single sentence is direct and front-loaded, but could include minimal context like returning the count as an integer.
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?
For a simple read-only counting tool with full annotations and output schema, the description is completely adequate.
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?
Input schema covers 100% of parameters with descriptions. Description adds no additional parameter meaning beyond what schema already provides.
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?
Description clearly states it counts records in an Odoo model with a domain filter, distinguishing it from siblings like search_records or read_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?
Description does not explicitly mention when to use this tool versus alternatives; usage is implied but not guided.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
create_recordB
Create new record(s) in an Odoo model.
| Name | Required | Description | Default |
|---|---|---|---|
| model | Yes | Model name (e.g., 'res.partner') | |
| values | Yes | Dictionary of field values, or list of dicts for batch creation |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, and the description does not disclose behavioral traits such as idempotency, error handling, authorization requirements, or side effects beyond creation.
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 concise sentence, front-loaded with the key action. It is not verbose, but could benefit from mentioning batch creation capability briefly.
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?
For a creation tool with no annotations, the description is minimal. It does not mention required permissions, success response, or batch behavior, despite having an output schema that could cover returns.
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?
Schema description coverage is 100%, so the description adds no additional meaning beyond what the schema already provides for both parameters (model and values). Baseline 3 is appropriate.
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 specifies the action 'create' and the resource 'record(s) in an Odoo model', which is distinct from sibling tools like update_record or delete_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?
No guidance on when to use this tool versus alternatives (e.g., update_record for modifications) or when not to use it. The description is silent on prerequisites or context.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
delete_recordADestructiveIdempotent
Delete records from an Odoo model. IRREVERSIBLE operation.
IMPORTANT: You MUST first call with confirm=False to show the user what will be deleted. Only set confirm=True AFTER the user explicitly approves the deletion. NEVER set confirm=True on the first call.
| Name | Required | Description | Default |
|---|---|---|---|
| model | Yes | Model name (e.g., 'res.partner') | |
| ids | Yes | List of record IDs to delete | |
| confirm | No | Safety flag. Always call with False first, then True only after user approval. |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description goes beyond annotations by emphasizing the irreversibility and the required two-step confirmation process. It adds critical behavioral context that annotations alone (destructiveHint, idempotentHint) do not fully convey.
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 concise and well-structured, with the action stated first, followed by a clear warning and step-by-step instructions. Every sentence adds value without 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 presence of an output schema and annotations covering destructiveness and idempotence, the description is complete. It provides all necessary safety protocol for a deletion operation, leaving no gaps in understanding.
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 already fully describes the three parameters with 100% coverage. The description reinforces the confirm parameter's usage but does not add new meaning beyond what the schema provides, so a baseline score of 3 is appropriate.
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?
Clearly states the action is deleting records from an Odoo model, using a specific verb and resource. The distinction from sibling tools like create_record and update_record is evident.
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?
Explicitly instructs to first call with confirm=False to preview deletion, then only set confirm=True after user approval. This provides clear when-to-use guidance and prevents misuse.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
execute_methodC
Execute any method on an Odoo model.
| Name | Required | Description | Default |
|---|---|---|---|
| model | Yes | Model name (e.g., 'res.partner') | |
| method | Yes | Method name to execute | |
| args | No | Positional arguments for the method | |
| kwargs | No | Keyword arguments for the method |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description bears full responsibility. It only states 'Execute any method' but omits critical behavioral traits such as potential destructive side effects, required permissions, or whether the method is idempotent. This is a major omission for such a powerful tool.
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 sentence, but it is too brief for the tool's complexity. Conciseness is good, but it sacrifices necessary detail, making it borderline under-specified.
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?
Despite having an output schema, the description does not mention return values. More critically, it lacks warnings about executing arbitrary methods, which is a safety concern. The tool's complexity demands far more context.
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?
Schema description coverage is 100%, with clear descriptions for model, method, args, and kwargs. The description adds no additional meaning beyond the schema, earning a baseline 3.
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 verb ('Execute') and resource ('any method on an Odoo model'). It distinguishes from siblings like 'create_record' or 'delete_record' which are specific CRUD operations, making it unique.
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?
No guidance on when or when not to use this tool. It does not compare to alternatives like 'create_record' or 'update_record' or mention prerequisites or typical use cases.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_fieldsARead-onlyIdempotent
Get field information for an Odoo model using ORM fields_get().
| Name | Required | Description | Default |
|---|---|---|---|
| model | Yes | Model name (e.g., 'res.partner') | |
| field_filter | No | Optional filter for field name (e.g., 'name' to find name-related fields) | |
| fields | No | Specific field names to retrieve (None = all fields) | |
| attributes | No | Field attributes to return (None = default attributes including type, string, help, required, readonly, store, selection, comodel_name, inverse_name, domain) |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and idempotentHint=true. The description adds that the tool uses the ORM's fields_get() method, but does not disclose additional behavioral traits like potential performance impact on large models or that it might return a large volume of data. Given the good annotation coverage, this is adequate but not exceptional.
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 sentence that immediately communicates purpose and method. It contains no filler or redundant information, making it optimally concise and 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?
For a read-only metadata retrieval tool with 4 parameters, full schema documentation, and an output schema, the description is mostly complete. It lacks mention of error cases (e.g., invalid model name) but these are partially covered by the schema descriptions. Overall, it is sufficient for an AI agent to understand basic functionality.
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?
Schema coverage is 100% with all four parameters described in the input schema. The description does not add any parameter-specific semantics beyond what the schema provides. The mention of using ORM fields_get() is a general context, not parameter detail. Baseline 3 is appropriate.
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 action ('Get field information'), the resource ('for an Odoo model'), and the method ('using ORM fields_get()'). It accurately distinguishes this tool from siblings like 'read_records' (which retrieve data rows) and 'list_models' (which list models) by specifying it returns field metadata.
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 no guidance on when to use this tool versus alternatives, such as 'execute_method' for calling fields_get generically, or 'list_models' for getting available models. There are no usage conditions, exclusions, or prerequisites mentioned.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_modelsARead-onlyIdempotent
List all available Odoo models.
| Name | Required | Description | Default |
|---|---|---|---|
| name_filter | No | Optional filter for model name (e.g., 'sale' to find sale-related models) |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint and idempotentHint as true, and the description adds no additional behavioral details beyond the simple listing operation.
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 concise sentence with no extraneous information, efficiently conveying the tool's purpose.
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 tool's simplicity, one parameter, and existing annotations/output schema, the description adequately covers the essentials; minor gap in clarifying 'available models' scope.
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?
Schema description coverage is 100%, so the schema already explains the optional name_filter parameter; the main description adds no further parameter context.
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 'List all available Odoo models' uses a specific verb and resource, clearly distinguishing it from sibling tools that operate on records rather than models.
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?
No explicit guidance on when to use this tool versus alternatives, but the context implies its use when discovering available models; lack of exclusions or alternatives mentioned.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
read_recordsARead-onlyIdempotent
Read specific records by their IDs.
| Name | Required | Description | Default |
|---|---|---|---|
| model | Yes | Model name (e.g., 'res.partner') | |
| ids | Yes | List of record IDs to read | |
| fields | No | Fields to return (None = auto-exclude dangerous fields like binary/image/html) |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already provide readOnlyHint=true and idempotentHint=true, so the description adds no new behavioral traits. It does not contradict annotations but also does not elaborate on what the tool returns or any side effects.
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?
Single sentence, front-loaded with key action and resource, no unnecessary words. Perfectly concise for a simple read tool.
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 tool's simplicity, annotations covering safety and idempotence, full schema documentation, and presence of output schema, the description is complete. No additional context needed.
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?
Schema has 100% description coverage, so the description adds little beyond 'by their IDs', which is already implied by the ids parameter. Baseline 3 applies as description is adequate but not enhancing.
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 verb 'Read' and resource 'records', specifying the mechanism 'by their IDs'. This distinguishes it from sibling tools like search_records and count_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?
No explicit when-to-use or when-not-to-use guidance is provided. While the purpose is clear, it does not differentiate from alternatives like search_records or get_fields, leaving the agent to infer contexts.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_recordsARead-onlyIdempotent
Search for records in an Odoo model.
| Name | Required | Description | Default |
|---|---|---|---|
| model | Yes | Model name (e.g., 'res.partner') | |
| domain | No | Odoo search domain (list of conditions). Examples: - Simple: [["name", "=", "John"]] - Multiple (AND): [["is_company", "=", True], ["active", "=", True]] - OR condition: ["|", ["name", "ilike", "test"], ["email", "ilike", "test"]] - any (Odoo 19+): [["order_line", "any", [["product_uom_qty", ">", 5]]]] - Operators: =, !=, >, >=, <, <=, like, ilike, in, not in, child_of, any | |
| fields | No | Fields to return (None = auto-exclude dangerous fields like binary/image/html) | |
| limit | No | Maximum number of records | |
| offset | No | Number of records to skip | |
| order | No | Sort order (e.g., 'name asc', 'create_date desc') |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and idempotentHint=true, so the safety profile is clear. The description adds no additional behavioral context (e.g., that results depend on model permissions or that it returns a list). Bar is lowered by good annotations, but the description does not add value beyond the schema.
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 sentence that efficiently states the tool's core function with no wasted words.
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 rich input schema and annotations, the description is minimally adequate but lacks context about usage scope (e.g., domain filtering) and return behavior. Output schema exists but is not referenced.
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?
Schema coverage is 100%, so every parameter has a description. The tool description does not add any info beyond the schema; baseline 3 is appropriate.
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 ('Search') and resource ('records in an Odoo model'), clearly distinguishing it from sibling tools like 'read_records' (read by ID) and 'count_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?
No guidance is provided on when to use this tool versus alternatives such as 'read_records' or 'count_records'. The description does not mention context or exclusions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
update_recordAIdempotent
Update existing records in an Odoo model.
| Name | Required | Description | Default |
|---|---|---|---|
| model | Yes | Model name (e.g., 'res.partner') | |
| ids | Yes | List of record IDs to update | |
| values | Yes | Dictionary of field values to update |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already provide idempotentHint: true. Description adds no extra behavioral context (e.g., what happens if record doesn't exist). It is adequate but does not go beyond the schema.
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?
Single sentence, no wasted words. Efficient, though could be slightly expanded with key usage details without losing conciseness.
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 and input schema fully describes parameters, the brief description is nearly sufficient. Minor lack of info about behavior on invalid IDs or return structure, but overall 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?
All 3 parameters have descriptions in the schema (100% coverage). The description adds no new meaning beyond what is already in the input schema.
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?
Description clearly states 'Update existing records in an Odoo model' – a specific verb and resource, and implicitly distinguishes from sibling tools like create_record and delete_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?
No explicit guidance on when to use or not use this tool vs alternatives. It is implied by context (update vs create/delete) but lacks explicit when-not-to-use or prerequisites.
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.
9 tool updates
- Changed
count_records2 fields changed- added
Input schema / properties / domain / descriptionAdded value: +"Odoo search domain (list of conditions). Examples:\n- Simple: [[\"active\", \"=\", True]]\n- Multiple (AND): [[\"is_company\", \"=\", True], [\"country_id\", \"=\", 1]]\n- OR condition: [\"|\", [\"type\", \"=\", \"contact\"], [\"type\", \"=\", \"invoice\"]]\n- any (Odoo 19+): [[\"order_line\", \"any\", [[\"product_uom_qty\", \">\", 5]]]]\n- Operators: =, !=, >, >=, <, <=, like, ilike, in, not in, child_of, any" - added
Input schema / properties / model / descriptionAdded value: +"Model name (e.g., 'res.partner')"
- Changed
create_record2 fields changed- added
Input schema / properties / model / descriptionAdded value: +"Model name (e.g., 'res.partner')" - added
Input schema / properties / values / descriptionAdded value: +"Dictionary of field values, or list of dicts for batch creation"
- Changed
delete_record3 fields changed- added
Input schema / properties / confirm / descriptionAdded value: +"Safety flag. Always call with False first, then True only after user approval." - added
Input schema / properties / ids / descriptionAdded value: +"List of record IDs to delete" - added
Input schema / properties / model / descriptionAdded value: +"Model name (e.g., 'res.partner')"
- Changed
execute_method4 fields changed- added
Input schema / properties / args / descriptionAdded value: +"Positional arguments for the method" - added
Input schema / properties / kwargs / descriptionAdded value: +"Keyword arguments for the method" - added
Input schema / properties / method / descriptionAdded value: +"Method name to execute" - added
Input schema / properties / model / descriptionAdded value: +"Model name (e.g., 'res.partner')"
- Changed
get_fields4 fields changed- added
Input schema / properties / attributes / descriptionAdded value: +"Field attributes to return (None = default attributes including\n type, string, help, required, readonly, store, selection,\n comodel_name, inverse_name, domain)" - added
Input schema / properties / field_filter / descriptionAdded value: +"Optional filter for field name (e.g., 'name' to find name-related fields)" - added
Input schema / properties / fields / descriptionAdded value: +"Specific field names to retrieve (None = all fields)" - added
Input schema / properties / model / descriptionAdded value: +"Model name (e.g., 'res.partner')"
- Changed
list_models1 field changed- added
Input schema / properties / name_filter / descriptionAdded value: +"Optional filter for model name (e.g., 'sale' to find sale-related models)"
- Changed
read_records3 fields changed- added
Input schema / properties / fields / descriptionAdded value: +"Fields to return (None = auto-exclude dangerous fields like binary/image/html)" - added
Input schema / properties / ids / descriptionAdded value: +"List of record IDs to read" - added
Input schema / properties / model / descriptionAdded value: +"Model name (e.g., 'res.partner')"
- Changed
search_records6 fields changed- added
Input schema / properties / domain / descriptionAdded value: +"Odoo search domain (list of conditions). Examples:\n- Simple: [[\"name\", \"=\", \"John\"]]\n- Multiple (AND): [[\"is_company\", \"=\", True], [\"active\", \"=\", True]]\n- OR condition: [\"|\", [\"name\", \"ilike\", \"test\"], [\"email\", \"ilike\", \"test\"]]\n- any (Odoo 19+): [[\"order_line\", \"any\", [[\"product_uom_qty\", \">\", 5]]]]\n- Operators: =, !=, >, >=, <, <=, like, ilike, in, not in, child_of, any" - added
Input schema / properties / fields / descriptionAdded value: +"Fields to return (None = auto-exclude dangerous fields like binary/image/html)" - added
Input schema / properties / limit / descriptionAdded value: +"Maximum number of records" - added
Input schema / properties / model / descriptionAdded value: +"Model name (e.g., 'res.partner')" - added
Input schema / properties / offset / descriptionAdded value: +"Number of records to skip" - added
Input schema / properties / order / descriptionAdded value: +"Sort order (e.g., 'name asc', 'create_date desc')"
- Changed
update_record3 fields changed- added
Input schema / properties / ids / descriptionAdded value: +"List of record IDs to update" - added
Input schema / properties / model / descriptionAdded value: +"Model name (e.g., 'res.partner')" - added
Input schema / properties / values / descriptionAdded value: +"Dictionary of field values to update"
9 tool updates
v1.0.0- First observed
count_records - First observed
create_record - First observed
delete_record - First observed
execute_method - First observed
get_fields - First observed
list_models - First observed
read_records - First observed
search_records - First observed
update_record
TDQS
Scored across 9 tools
Each tool has a distinct purpose: count, create, delete, execute method, get fields, list models, read, search, update. No two tools overlap in functionality.
All tool names follow a consistent verb_noun pattern in snake_case (e.g., count_records, create_record, list_models), making it predictable and easy to understand.
9 tools is well-scoped for an Odoo server, covering essential operations without being too few or too many.
The set includes CRUD operations, search, count, field introspection, model listing, and arbitrary method execution, providing comprehensive coverage for interacting with Odoo models.
Maintenance
Related MCP Connectors
MCP server for Product Management
MCP server for the Seline Analytics API
MCP server unifying ERPs, CRMs, APIs and knowledge base for Claude, ChatGPT and Gemini.
Related MCP Servers
- 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
- FlicenseNot gradedqualityDmaintenanceMCP server for interacting with Odoo/ODX resources via ODXProxy, enabling programmatic access for MCP-compatible clients.1-
- FlicenseNot gradedqualityDmaintenanceMCP server to connect Claude with Odoo 18, enabling CRUD operations on Odoo models via natural language.2-
- AlicenseNot gradedqualityDmaintenanceA professional MCP server for seamless Odoo ERP integration, supporting HTTP and STDIO transports.10 npmMIT