odoo-rust-mcp

mcp
Guvenlik Denetimi
Basarisiz
Health Gecti
  • License — License: AGPL-3.0
  • Description — Repository has a description
  • Active repo — Last push 0 days ago
  • Community trust — 14 GitHub stars
Code Basarisiz
  • rm -rf — Recursive force deletion command in .github/workflows/ci.yml
  • rm -rf — Recursive force deletion command in .github/workflows/release.yml
  • Hardcoded secret — Potential hardcoded credential in config-ui/src/__tests__/integration.test.ts
Permissions Gecti
  • Permissions — No dangerous permissions requested

Bu listing icin henuz AI raporu yok.

SUMMARY

Odoo MCP Server - Model Context Protocol server for Odoo ERP integration. Supports Odoo 14-19+ with JSON-RPC and REST API.

README.md

odoo-rust-mcp 🚗

CI
Release
codecov
GitHub release
License: AGPL-3.0
Homebrew
Debian/Ubuntu
Docker
Kubernetes
Helm

Inspired by Peugeot 3008 - Elegant, innovative, and reliable. Just like the Peugeot 3008 SUV combines style with performance, this MCP server combines elegance with powerful Odoo integration capabilities.

Rust implementation of an Odoo MCP server (Model Context Protocol), supporting:

  • Odoo 19+: JSON-2 External API (/json/2/...) with API key authentication
  • Odoo < 19: JSON-RPC (/jsonrpc) with username/password authentication

Features

  • MCP over stdio (Cursor / Claude Desktop style)
  • MCP over Streamable HTTP (Cursor remote transport)
  • MCP over SSE (legacy HTTP+SSE transport)
  • MCP over WebSocket (standalone server; not used by Cursor)
  • Web UI for configuration on port 3008 (tools, prompts, server, instances JSON) - Inspired by Peugeot 3008's elegant design
  • Multi-instance support via ODOO_INSTANCES
  • Metadata caching with configurable TTL to reduce Odoo API calls
  • Health check endpoint for monitoring and configuration validation
  • MCP Resources with odoo:// URI scheme for resource discovery
  • New tools: list models, check access rights, bulk create
  • Optional cleanup tools gated behind ODOO_ENABLE_CLEANUP_TOOLS=true

Repository layout

  • rust-mcp/: the Rust MCP server implementation (Cargo workspace root)

Requirements

  • Rust toolchain (cargo)
  • Odoo instance:
    • Odoo 19+: Requires External JSON-2 API and API keys
    • Odoo < 19: Works with standard JSON-RPC endpoint (username/password)

Notes: For Odoo 19+, access to JSON-2 external API is only available on Custom plans. For Odoo < 19, the standard JSON-RPC endpoint is used which is available on all editions.

Configuration (environment variables)

Multi-instance (recommended)

Option A: JSON file (recommended for readability)

See instances.example.json in the repository root for a complete example configuration.

Create ~/.config/odoo-rust-mcp/instances.json:

{
  "production": {
    "url": "https://mycompany.example.com",
    "db": "mycompany",
    "apiKey": "YOUR_API_KEY"
  },
  "staging": {
    "url": "https://staging.mycompany.example.com",
    "apiKey": "YOUR_API_KEY"
  },
  "legacy": {
    "url": "https://legacy.mycompany.example.com",
    "db": "legacy_db",
    "version": "18",
    "username": "admin",
    "password": "admin_password"
  }
}

Then in ~/.config/odoo-rust-mcp/env:

ODOO_INSTANCES_JSON=/path/to/instances.json

Option B: Inline JSON (single line)

Set ODOO_INSTANCES directly in env file (must be single line):

ODOO_INSTANCES={"production":{"url":"https://mycompany.example.com","apiKey":"xxx"},"staging":{"url":"https://staging.example.com","apiKey":"yyy"}}

Instance configuration fields:

Field Required Description
url Yes Odoo server URL
db Odoo < 19 Database name (required for legacy, optional for 19+)
apiKey Odoo 19+ API key for authentication
version No Odoo version (e.g., "17", "18"). If < 19, uses username/password
username Odoo < 19 Username for JSON-RPC authentication
password Odoo < 19 Password for JSON-RPC authentication

Notes:

  • db is optional for Odoo 19+ (only needed when Host header isn't enough to select DB).
  • db is required for Odoo < 19 (legacy mode).
  • version determines authentication mode: < 19 uses username/password, >= 19 uses API key.
  • Extra fields in the JSON are ignored.
  • If an instance omits apiKey, the server will fall back to the global ODOO_API_KEY (if set).
  • If an instance omits username/password, the server will fall back to ODOO_USERNAME/ODOO_PASSWORD.

Single-instance (fallback)

Odoo 19+ (API Key):

export ODOO_URL="https://mycompany.example.com"
export ODOO_API_KEY="YOUR_API_KEY"
export ODOO_DB="mycompany"   # optional

Odoo < 19 (Username/Password):

export ODOO_URL="https://mycompany.example.com"
export ODOO_DB="mycompany"   # required for legacy
export ODOO_VERSION="18"     # triggers legacy mode
export ODOO_USERNAME="admin"
export ODOO_PASSWORD="your_password"

URL convenience: ODOO_URL may be given as localhost:8069 (it will be normalized to http://localhost:8069).

Local example (Odoo 19+)

export ODOO_URL="localhost:8069"
export ODOO_DB="v19_pos"
export ODOO_API_KEY="YOUR_API_KEY"

Local example (Odoo 18 or earlier)

export ODOO_URL="localhost:8069"
export ODOO_DB="v18_db"
export ODOO_VERSION="18"
export ODOO_USERNAME="admin"
export ODOO_PASSWORD="admin"

Tools, prompts, and server metadata via JSON (no recompile)

This server is fully declarative:

  • tools.json defines:
    • tool name / description
    • tool inputSchema (JSON Schema; must be Cursor-friendly)
    • tool op (maps tool calls to a primitive operation executed by Rust)
    • optional guards (e.g. requiresEnvTrue)
  • prompts.json defines prompt name / description / content
  • server.json defines initialize metadata (serverName, instructions, default protocol version)

Cursor schema constraints:

  • Avoid anyOf, oneOf, allOf, $ref, definitions, and \"type\": [...] (type arrays). These are rejected to prevent Cursor schema parsing issues.

Auto-reload:

  • The server watches these files and reloads them on change.
  • If a JSON file is missing at startup, the server will create it from built-in seed defaults (embedded from rust-mcp/config-defaults/*).

Editable vs seed defaults (important):

  • Edit these runtime files for day-to-day configuration:
    • rust-mcp/config/tools.json
    • rust-mcp/config/prompts.json
    • rust-mcp/config/server.json
  • Do not edit rust-mcp/config-defaults/* for normal configuration changes.
    • Those files are embedded into the binary as seed defaults (used only to auto-create missing runtime config files).
    • If you change config-defaults/*, you must rebuild the binary/image for changes to take effect.

Environment variables (optional overrides):

export MCP_TOOLS_JSON="config/tools.json"
export MCP_PROMPTS_JSON="config/prompts.json"
export MCP_SERVER_JSON="config/server.json"

Automatic Configuration Path Setup:

For new installations (Homebrew, APT, direct binary), the following environment variables are automatically set in your .env file:

# MCP Config paths (using user config directory)
MCP_TOOLS_JSON=/Users/username/.config/odoo-rust-mcp/tools.json
MCP_PROMPTS_JSON=/Users/username/.config/odoo-rust-mcp/prompts.json
MCP_SERVER_JSON=/Users/username/.config/odoo-rust-mcp/server.json

For existing users upgrading, these variables are automatically added to your .env file during the first run after upgrade. Default config files (tools.json, prompts.json, server.json) are also automatically copied to your config directory if they don't exist.

Sample files are provided in:

  • rust-mcp/config/tools.json
  • rust-mcp/config/prompts.json
  • rust-mcp/config/server.json

Seed defaults (used only when files are missing):

  • rust-mcp/config-defaults/tools.json
  • rust-mcp/config-defaults/prompts.json
  • rust-mcp/config-defaults/server.json

Disabling Tools

To disable specific tools (e.g., create and update operations for read-only access), you have two options:

Option 1: Remove tools from the array (recommended)

Simply remove the tool entries from the tools array in tools.json. For example, to disable odoo_create and odoo_update:

{
  "tools": [
    {
      "name": "odoo_search",
      ...
    },
    {
      "name": "odoo_search_read",
      ...
    },
    {
      "name": "odoo_read",
      ...
    }
    // odoo_create and odoo_update are removed - they won't be available
  ]
}

Option 2: Use guards for conditional disabling

Use guards with requiresEnvTrue to conditionally enable/disable tools based on environment variables:

{
  "tools": [
    {
      "name": "odoo_create",
      "description": "Create a new Odoo record...",
      "guards": {
        "requiresEnvTrue": "ODOO_ENABLE_WRITE_OPERATIONS"
      },
      "inputSchema": { ... },
      "op": { ... }
    },
    {
      "name": "odoo_update",
      "description": "Update existing Odoo records...",
      "guards": {
        "requiresEnvTrue": "ODOO_ENABLE_WRITE_OPERATIONS"
      },
      "inputSchema": { ... },
      "op": { ... }
    }
  ]
}

Then set the environment variable to enable:

export ODOO_ENABLE_WRITE_OPERATIONS=true

Example: Read-only configuration

Here's a minimal tools.json for read-only access (no create, update, delete, or batch operations):

{
  "tools": [
    {
      "name": "odoo_search",
      "description": "Search for Odoo records...",
      "inputSchema": { ... },
      "op": { "type": "search", "map": { ... } }
    },
    {
      "name": "odoo_search_read",
      "description": "Search and read Odoo records...",
      "inputSchema": { ... },
      "op": { "type": "search_read", "map": { ... } }
    },
    {
      "name": "odoo_read",
      "description": "Read specific Odoo records...",
      "inputSchema": { ... },
      "op": { "type": "read", "map": { ... } }
    },
    {
      "name": "odoo_count",
      "description": "Count records matching domain...",
      "inputSchema": { ... },
      "op": { "type": "search_count", "map": { ... } }
    },
    {
      "name": "odoo_get_model_metadata",
      "description": "Get model metadata...",
      "inputSchema": { ... },
      "op": { "type": "get_model_metadata", "map": { ... } }
    },
    {
      "name": "odoo_list_models",
      "description": "List available Odoo models...",
      "inputSchema": { ... },
      "op": { "type": "list_models", "map": { ... } }
    }
    // Note: odoo_create, odoo_update, odoo_delete, odoo_create_batch are excluded
  ]
}

After modifying tools.json, the server will automatically reload the configuration (no restart needed).

Advanced Features

Metadata Caching

The server caches Odoo model metadata to reduce repeated API calls. Configure cache TTL:

export ODOO_METADATA_CACHE_TTL_SECS=3600  # default: 1 hour

Cache is in-memory and shared across all instances. Useful for reducing latency when working with large models or frequent metadata queries.

Health Check Endpoint

When running in HTTP mode, a health check endpoint is available:

GET /health

Response:

{
  "status": "ok",
  "version": "0.3.0",
  "instance": {
    "name": "default",
    "reachable": true
  }
}

Configuration Validation

Validate your Odoo instance configuration before starting the server:

./rust-mcp validate-config

This command tests connectivity to all configured instances and reports any authentication or connection issues.

MCP Resources

The server exposes Odoo resources via the MCP Resources protocol using odoo:// URIs:

  • odoo://instances - List configured Odoo instances
  • odoo://{instance}/models - List accessible models in an instance
  • odoo://{instance}/metadata/{model} - Get field metadata for a model

MCP clients that support resources can use these to discover available Odoo models and fields dynamically.

Configuration Server (Web UI)

A web-based configuration interface is available on port 3008 for managing tools.json, prompts.json, server.json, and instances.json without manual file editing. The port number is inspired by the Peugeot 3008 - a symbol of elegance, innovation, and reliability.

Access the config UI:

  • Local: http://localhost:3008
  • Docker Compose: http://localhost:3008 or via Traefik http://mcp-config.localhost
  • Kubernetes: Exposed via service on port 3008

Features:

  • Authentication: Secure login with username/password (configurable via .env)
  • Edit all JSON configuration files via interactive UI
  • Real-time JSON validation before saving with automatic rollback on errors
  • Error handling: Automatic backup and restore if configuration becomes corrupted
  • MCP HTTP Auth Management: Enable/disable authentication and generate tokens directly from UI
  • Config UI Credentials Management: Change login username and password from the UI
  • Tool enable/disable checkboxes (e.g., toggle ODOO_ENABLE_CLEANUP_TOOLS)
  • Automatic file watching and hot reload (no server restart needed)
  • User notifications: Success, error, and warning messages displayed in the UI
  • REST API endpoints for programmatic access:
    • GET /api/config/{instances|tools|prompts|server} - Retrieve config
    • POST /api/config/{instances|tools|prompts|server} - Update config
    • GET /api/config/auth/status - Get MCP auth status
    • POST /api/config/auth/enable - Enable/disable MCP HTTP auth
    • POST /api/config/auth/token/generate - Generate new MCP auth token
    • POST /api/config/auth/credentials - Update Config UI credentials
    • GET /health - Health check

Environment variables:

# Config server port
export ODOO_CONFIG_SERVER_PORT=3008  # default: 3008 (inspired by Peugeot 3008)

# Config UI Authentication (default credentials)
export CONFIG_UI_USERNAME=admin      # default: admin
export CONFIG_UI_PASSWORD=changeme   # default: changeme (CHANGE THIS!)

# MCP HTTP Transport Authentication
export MCP_AUTH_ENABLED=false        # default: false
export MCP_AUTH_TOKEN=               # Bearer token (generate: openssl rand -hex 32)

First-time setup:

  1. Open http://localhost:3008
  2. Login with default credentials (admin / changeme)
  3. IMPORTANT: Go to Security tab and change the default password immediately
  4. Configure your Odoo instances in the Instances tab
  5. Optionally enable MCP HTTP authentication from the Security tab

Example: Enable/disable cleanup tools via UI

  1. Open http://localhost:3008 and login
  2. Go to Tools tab
  3. Find the odoo_create_batch tool (or other cleanup operations)
  4. Toggle the ODOO_ENABLE_CLEANUP_TOOLS checkbox
  5. Save changes (file is auto-reloaded)

Example: Enable MCP HTTP Authentication

  1. Open http://localhost:3008 and login
  2. Go to Security tab
  3. Toggle Enable MCP HTTP Authentication
  4. Click Generate New Token (or use existing token)
  5. Changes apply immediately (hot-reload, no restart needed)
  6. Use the token in your MCP client configuration:
{
  "mcpServers": {
    "odoo-rust-mcp": {
      "url": "http://127.0.0.1:8787/mcp",
      "headers": {
        "Authorization": "Bearer your-generated-token-here"
      }
    }
  }
}

Security Notes:

  • Config UI credentials are stored in .env file (not in JSON configs)
  • MCP auth settings are also stored in .env and can be hot-reloaded
  • All configuration changes are validated before saving
  • Automatic backup and rollback prevent configuration corruption
  • For production, use strong passwords and secure tokens

Installation

Option 1: Homebrew (macOS/Linux) - Recommended

# Install
brew tap rachmataditiya/odoo-rust-mcp
brew install rust-mcp

# Configure (edit with your Odoo credentials)
nano ~/.config/odoo-rust-mcp/env

# Start as background service
brew services start rust-mcp

Or install directly in one command:

brew install rachmataditiya/odoo-rust-mcp/rust-mcp

What gets installed:

Component Location
Binary /opt/homebrew/bin/rust-mcp
Service wrapper /opt/homebrew/bin/rust-mcp-service
User configs ~/.config/odoo-rust-mcp/ (auto-created)
Service logs /opt/homebrew/var/log/rust-mcp.log

User config directory (~/.config/odoo-rust-mcp/):

├── env              # Environment variables - EDIT THIS with Odoo credentials
├── tools.json       # MCP tools definition
├── prompts.json     # MCP prompts definition  
└── server.json      # MCP server metadata

Service commands:

brew services start rust-mcp      # Start service
brew services stop rust-mcp       # Stop service
brew services restart rust-mcp    # Restart after config changes
brew services list                # Check status
tail -f /opt/homebrew/var/log/rust-mcp.log  # View logs

Service endpoint: http://127.0.0.1:8787/mcp

For Cursor/Claude Desktop/Windsurf with Homebrew:

The binary automatically loads config from ~/.config/odoo-rust-mcp/env, so you can use it directly:

{
  "mcpServers": {
    "odoo": {
      "command": "/opt/homebrew/bin/rust-mcp",
      "args": ["--transport", "stdio"]
    }
  }
}

Note: Starting from v0.2.4, the binary (rust-mcp) automatically:

  • Creates ~/.config/odoo-rust-mcp/ directory if it doesn't exist
  • Creates a default env template file with multi-instance configuration
  • Loads environment variables from ~/.config/odoo-rust-mcp/env
  • Sets default MCP config paths (MCP_TOOLS_JSON, MCP_PROMPTS_JSON, MCP_SERVER_JSON) pointing to user config directory
  • Copies default config files from Homebrew share directory if they don't exist
  • Migrates existing single-instance configurations to instances.json format
  • Adds missing environment variables (like CONFIG_UI_USERNAME, CONFIG_UI_PASSWORD, MCP_AUTH_ENABLED) to existing .env files

This means you can use rust-mcp directly without the shell wrapper rust-mcp-service. This is especially important for MCP clients like Windsurf that don't support shell script execution.

For full Homebrew documentation, see: https://rachmataditiya.github.io/homebrew-odoo-rust-mcp/

Option 2: APT (Debian/Ubuntu)

# Add GPG key
curl -fsSL https://rachmataditiya.github.io/odoo-rust-mcp/pubkey.gpg | sudo gpg --dearmor -o /usr/share/keyrings/rust-mcp.gpg

# Add repository
echo "deb [signed-by=/usr/share/keyrings/rust-mcp.gpg] https://rachmataditiya.github.io/odoo-rust-mcp stable main" | sudo tee /etc/apt/sources.list.d/rust-mcp.list

# Install
sudo apt update
sudo apt install rust-mcp

# Configure (edit with your Odoo credentials)
nano ~/.config/rust-mcp/env

# Start service
sudo systemctl start rust-mcp
sudo systemctl enable rust-mcp

What gets installed:

Component Location
Binary /usr/bin/rust-mcp
Service wrapper /usr/bin/rust-mcp-service
Default configs /usr/share/rust-mcp/
User configs ~/.config/rust-mcp/ (auto-created on install)
Systemd service /lib/systemd/system/rust-mcp.service

Service commands:

sudo systemctl start rust-mcp      # Start service
sudo systemctl stop rust-mcp       # Stop service
sudo systemctl restart rust-mcp    # Restart after config changes
sudo systemctl status rust-mcp     # Check status
journalctl -u rust-mcp -f          # View logs

Service endpoint: http://127.0.0.1:8787/mcp

Option 3: Download and install

Download the latest release for your platform from GitHub Releases:

Platform File
Linux x86_64 rust-mcp-x86_64-unknown-linux-gnu.tar.gz
macOS x86_64 rust-mcp-x86_64-apple-darwin.tar.gz
macOS ARM64 (Apple Silicon) rust-mcp-aarch64-apple-darwin.tar.gz
Windows x86_64 rust-mcp-x86_64-pc-windows-msvc.zip

Extract and install:

Linux / macOS:

tar -xzf rust-mcp-<platform>.tar.gz
cd rust-mcp-<platform>
./install.sh

This installs:

  • Binary to /usr/local/bin/rust-mcp
  • Config files to /usr/local/share/odoo-rust-mcp/

To uninstall:

./install.sh uninstall

Windows (PowerShell as Administrator):

Expand-Archive rust-mcp-x86_64-pc-windows-msvc.zip -DestinationPath rust-mcp
cd rust-mcp
.\install.ps1

This installs:

  • Binary to C:\Program Files\odoo-rust-mcp\
  • Config files to C:\ProgramData\odoo-rust-mcp\
  • Adds binary to system PATH

To uninstall:

.\install.ps1 -Uninstall

Manual (without installer):

# Linux/macOS - just run directly
tar -xzf rust-mcp-<platform>.tar.gz
./rust-mcp --transport stdio

# Windows
Expand-Archive rust-mcp-x86_64-pc-windows-msvc.zip -DestinationPath .
.\rust-mcp.exe --transport stdio

The release archive includes:

  • rust-mcp (or rust-mcp.exe on Windows) - the binary
  • config/ - default configuration files (tools.json, prompts.json, server.json)
  • .env.example - example environment variables
  • install.sh (Linux/macOS) or install.ps1 (Windows) - installer script

Option 4: Build from source

cd rust-mcp
cargo build --release

Run as Background Service

The installer scripts support running the MCP server as a background service (HTTP transport on port 8787).

Linux (systemd):

./install.sh service

Commands:

  • Start: sudo systemctl start odoo-rust-mcp
  • Stop: sudo systemctl stop odoo-rust-mcp
  • Status: sudo systemctl status odoo-rust-mcp
  • Logs: sudo journalctl -u odoo-rust-mcp -f

Config: /etc/odoo-rust-mcp.env

macOS (launchd):

./install.sh service

Commands:

  • Start: launchctl load ~/Library/LaunchAgents/com.odoo.rust-mcp.plist
  • Stop: launchctl unload ~/Library/LaunchAgents/com.odoo.rust-mcp.plist
  • Logs: tail -f ~/.config/odoo-rust-mcp/stdout.log

Config: ~/.config/odoo-rust-mcp/env

Windows (Scheduled Task):

.\install.ps1 -Service

Commands (PowerShell as Admin):

  • Start: Start-ScheduledTask -TaskName OdooRustMcpService
  • Stop: Stop-ScheduledTask -TaskName OdooRustMcpService
  • Status: Get-ScheduledTask -TaskName OdooRustMcpService | Select-Object State

Config: C:\ProgramData\odoo-rust-mcp\env.ps1

Service endpoint: http://127.0.0.1:8787/mcp

To remove service only:

# Linux/macOS
./install.sh service-uninstall

# Windows
.\install.ps1 -ServiceUninstall

Run (stdio)

cd rust-mcp
./target/release/rust-mcp --transport stdio

Run (Streamable HTTP)

cd rust-mcp
./target/release/rust-mcp --transport http --listen 127.0.0.1:8787

Endpoints:

  • Streamable HTTP: http://127.0.0.1:8787/mcp
  • Legacy SSE: http://127.0.0.1:8787/sse (paired with POST /messages)
  • Health check: http://127.0.0.1:8787/health (no auth required)
  • OpenAPI spec: http://127.0.0.1:8787/openapi.json (no auth required)

Streamable HTTP Transport (MCP 2025-11-25)

The HTTP transport implements the MCP Streamable HTTP specification (version 2025-11-25), which provides efficient real-time communication using Server-Sent Events (SSE).

Endpoints:

Method Path Description
POST /mcp Send JSON-RPC requests/notifications
GET /mcp Open SSE stream for server-to-client messages
DELETE /mcp Explicitly terminate a session

Features:

  • Session Management: Sessions are created on initialize and tracked via MCP-Session-Id header
  • SSE Streaming: Server can push notifications and progress updates via GET /mcp
  • Event IDs: Each SSE event has a unique ID for resumability support
  • Protocol Version Header: MCP-Protocol-Version header for version negotiation
  • Origin Validation: Security protection against DNS rebinding attacks

Headers:

Header Description
MCP-Session-Id Session identifier (returned on initialize, required for subsequent requests)
MCP-Protocol-Version Protocol version (e.g., 2025-03-26, 2025-11-05)
Authorization Bearer token authentication (if MCP_AUTH_TOKEN is set)
Last-Event-ID Resume SSE stream from a specific event (for reconnection)

Example: Initialize session

curl -X POST http://127.0.0.1:8787/mcp \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-03-26"}}'

Response includes MCP-Session-Id header for subsequent requests.

Example: Open SSE stream

curl -N http://127.0.0.1:8787/mcp \
  -H "Accept: text/event-stream" \
  -H "MCP-Session-Id: <session-id>"

Example: Terminate session

curl -X DELETE http://127.0.0.1:8787/mcp \
  -H "MCP-Session-Id: <session-id>"

Security Configuration:

# Enable Origin validation (comma-separated list of allowed origins)
export MCP_ALLOWED_ORIGINS="https://example.com,https://app.example.com"

# Localhost-only mode (empty value)
export MCP_ALLOWED_ORIGINS=""

# Disable Origin validation (default - not recommended for production)
# Simply don't set MCP_ALLOWED_ORIGINS

When Origin validation is enabled:

  • Requests with invalid Origin header receive 403 Forbidden
  • Localhost origins (localhost, 127.0.0.1, [::1]) are always allowed
  • Requests without Origin header (same-origin or non-browser clients) are allowed

HTTP API Documentation

The HTTP API is documented using OpenAPI 3.0 specification. You can:

  • View the OpenAPI spec: http://localhost:8787/openapi.json
  • Use the spec with tools like Swagger UI, Postman, or n8n for integration
  • The spec documents all endpoints including request/response schemas

For integration with tools like n8n or Dify, refer to the OpenAPI specification for complete API details.

Authentication (HTTP Transport)

The HTTP transport supports Bearer token authentication as per the MCP specification.

Enable authentication via environment variables:

export MCP_AUTH_ENABLED=true
export MCP_AUTH_TOKEN=your-secure-random-token-here

Or enable via Config UI (recommended):

  1. Open http://localhost:3008 and login
  2. Go to Security tab
  3. Toggle Enable MCP HTTP Authentication
  4. Click Generate New Token or paste your existing token
  5. Changes apply immediately (hot-reload, no restart needed)

When MCP_AUTH_ENABLED=true and MCP_AUTH_TOKEN is set, all HTTP requests must include the Authorization header:

Authorization: Bearer your-secure-random-token-here

Example with curl:

curl -X POST http://127.0.0.1:8787/mcp \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer your-secure-random-token-here" \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05"}}'

Hot-Reload Support:

  • Authentication settings can be enabled/disabled and tokens can be regenerated from the Config UI
  • Changes take effect immediately without restarting the service
  • The server uses Arc<RwLock> for thread-safe, dynamic configuration updates

Notes:

  • If MCP_AUTH_ENABLED=false or MCP_AUTH_TOKEN is not set, authentication is disabled (not recommended for production)
  • STDIO transport does not use HTTP authentication (credentials come from environment)
  • Generate a secure token: openssl rand -hex 32
  • For production deployments, always enable authentication

Run (WebSocket / standalone server)

cd rust-mcp
./target/release/rust-mcp --transport ws --listen 127.0.0.1:8787

Run with Docker Compose

Create .env in the repo root (example in dotenv.example), then:

docker compose up --build

By default, the container runs HTTP transport and exposes http://localhost:8787/mcp.

Features:

  • Custom network mcp-network for integration with other containers (n8n, dify, etc.)
  • Health check for container orchestration
  • Volume mounts for config files
  • Support for ODOO_INSTANCES_JSON for multi-instance setup
  • Resource limits and labels for service discovery

Multi-instance configuration:

  1. Create instances.json with your Odoo instances:
{
  "production": {"url": "https://odoo.example.com", "db": "prod", "apiKey": "xxx"},
  "staging": {"url": "https://staging.example.com", "db": "staging", "apiKey": "yyy"}
}
  1. Mount and configure in .env:
ODOO_INSTANCES_JSON=/config/instances.json
  1. Uncomment the volume mount in docker-compose.yml:
volumes:
  - ./instances.json:/config/instances.json:ro

Integration with other containers:

The MCP server runs on the mcp-network network. Other containers can connect using:

# In your other service's docker-compose.yml
services:
  n8n:
    networks:
      - mcp-network
    environment:
      MCP_URL: "http://odoo-mcp:8787/mcp"

networks:
  mcp-network:
    external: true

See docker-compose.override.example.yml for more integration examples.

Run with Kubernetes

The project includes Kubernetes manifests in k8s/ for production deployments.

Quick start with raw manifests:

# Apply all manifests
kubectl apply -k k8s/

# Or apply individually
kubectl apply -f k8s/namespace.yaml
kubectl apply -f k8s/configmap.yaml
kubectl apply -f k8s/secret.yaml    # Edit first with your credentials!
kubectl apply -f k8s/deployment.yaml
kubectl apply -f k8s/service.yaml
kubectl apply -f k8s/ingress.yaml   # Optional, for external access

Verify deployment:

kubectl -n odoo-mcp get pods
kubectl -n odoo-mcp logs -f deployment/odoo-mcp

Port-forward for local testing:

kubectl -n odoo-mcp port-forward svc/odoo-mcp 8787:8787
# Access: http://127.0.0.1:8787/mcp

Features:

  • Namespace isolation
  • ConfigMap for MCP configuration files
  • Secret for Odoo credentials
  • Deployment with:
    • Resource limits/requests
    • Liveness/readiness/startup probes
    • Pod anti-affinity for high availability
    • Non-root security context
  • ClusterIP Service for internal access
  • Ingress for external access with TLS
  • Kustomization for environment management

Run with Helm

For more flexible deployments, use the Helm chart in helm/odoo-rust-mcp/.

Install:

# Add your values (see helm/odoo-rust-mcp/values.yaml for all options)
cat > my-values.yaml <<EOF
odoo:
  url: "http://odoo-service:8069"
  db: "mydb"
  apiKey: "your-api-key"

mcp:
  authToken: "your-secure-token"

ingress:
  enabled: true
  hosts:
    - host: mcp.example.com
      paths:
        - path: /
          pathType: Prefix
EOF

# Install
helm install odoo-mcp ./helm/odoo-rust-mcp -f my-values.yaml -n odoo-mcp --create-namespace

Upgrade:

helm upgrade odoo-mcp ./helm/odoo-rust-mcp -f my-values.yaml -n odoo-mcp

Uninstall:

helm uninstall odoo-mcp -n odoo-mcp

Key configuration options:

Parameter Description Default
replicaCount Number of replicas 2
odoo.url Odoo server URL http://odoo-service:8069
odoo.apiKey API key for Odoo 19+ ""
odooInstances.json Multi-instance JSON config ""
mcp.authToken HTTP auth token (recommended) ""
ingress.enabled Enable ingress false
autoscaling.enabled Enable HPA false

Production recommendations:

  1. Always set mcp.authToken for HTTP authentication
  2. Use external secrets (Vault, AWS Secrets Manager) instead of storing credentials in values.yaml
  3. Enable pod disruption budgets for zero-downtime updates
  4. Configure resource limits based on your workload
  5. Use Ingress with TLS for external access

Cleanup tools (disabled by default)

Cleanup tools are only listed and callable when enabled:

export ODOO_ENABLE_CLEANUP_TOOLS=true

Tools

Tools are defined by tools.json (authoritative). The default seed includes tools like:

  • odoo_search, odoo_search_read, odoo_read, odoo_create, odoo_update, odoo_delete
  • odoo_execute, odoo_count, odoo_workflow_action, odoo_generate_report, odoo_get_model_metadata
  • odoo_list_models, odoo_check_access, odoo_create_batch
  • cleanup tools (odoo_database_cleanup, odoo_deep_cleanup) guarded by ODOO_ENABLE_CLEANUP_TOOLS=true

Supported op.type values (used in tools.json):

  • search, search_read, read, create, write, unlink
  • search_count, workflow_action, execute
  • generate_report, get_model_metadata
  • list_models, check_access, create_batch
  • database_cleanup, deep_cleanup

Prompts

Prompts are defined by prompts.json (authoritative). The default seed includes:

  • odoo_common_models
  • odoo_domain_filters

Example tool calls

Tool result format (important)

Most tools return an MCP response whose content[0].text is a JSON string.

  • In the examples below, Request shows what you pass as tool arguments.
  • Decoded result shows the JSON payload after you parse content[0].text.

Search and read:

{
  "instance": "default",
  "model": "res.partner",
  "domain": [["is_company", "=", true]],
  "fields": ["name", "email"],
  "limit": 10,
  "order": "name ASC"
}

Decoded result (shape):

{
  "records": [],
  "count": 0
}

Read by ids:

{
  "instance": "default",
  "model": "res.partner",
  "ids": [1, 2, 3],
  "fields": ["id", "name", "email"]
}

Decoded result (shape):

{
  "records": []
}

Create:

{
  "instance": "default",
  "model": "res.partner",
  "values": {
    "name": "ACME Demo",
    "is_company": true
  }
}

Decoded result (shape):

{
  "id": 123,
  "success": true
}

Update:

{
  "instance": "default",
  "model": "res.partner",
  "ids": [123],
  "values": {
    "email": "[email protected]"
  }
}

Decoded result (shape):

{
  "success": true,
  "updated_count": 1
}

Delete:

{
  "instance": "default",
  "model": "res.partner",
  "ids": [123]
}

Decoded result (shape):

{
  "success": true,
  "deleted_count": 1
}

Search (IDs only):

{
  "instance": "default",
  "model": "res.partner",
  "domain": [["is_company", "=", true]],
  "limit": 10,
  "order": "name ASC"
}

Decoded result (shape):

{
  "ids": [1, 2, 3],
  "count": 3
}

Count:

{
  "instance": "default",
  "model": "res.partner",
  "domain": [["id", ">", 0]]
}

Decoded result (shape):

{
  "count": 18
}

Execute action/button (workflow):

{
  "instance": "default",
  "model": "sale.order",
  "ids": [42],
  "action": "action_confirm"
}

Decoded result (shape):

{
  "result": null,
  "executed_on": [42]
}

Execute arbitrary method:

{
  "instance": "default",
  "model": "res.partner",
  "method": "name_get",
  "args": [[1, 2, 3]]
}

Decoded result (shape):

{
  "result": []
}

Model metadata (fields/types):

{
  "instance": "default",
  "model": "sale.order"
}

Decoded result (shape):

{
  "model": {
    "name": "sale.order",
    "description": "Sales Order",
    "fields": {}
  }
}

Generate report (PDF as base64):

{
  "instance": "default",
  "reportName": "sale.report_saleorder",
  "ids": [42]
}

Decoded result (shape):

{
  "pdf_base64": "JVBERi0xLjQKJ...<omitted>...",
  "report_name": "sale.report_saleorder",
  "record_ids": [42]
}

List models (with optional filtering):

{
  "instance": "default",
  "domain": [["transient", "=", false]],
  "limit": 50,
  "offset": 0
}

Decoded result (shape):

{
  "models": [
    {"id": 2, "model": "ir.actions", "name": "Actions"},
    {"id": 3, "model": "ir.model", "name": "Models"}
  ]
}

Check access rights:

{
  "instance": "default",
  "model": "res.partner",
  "operation": "write",
  "ids": [1, 2, 3]
}

Decoded result (shape):

{
  "has_access": true,
  "model": "res.partner",
  "operation": "write",
  "model_level": true,
  "record_level": true
}

Bulk create records (max 100):

{
  "instance": "default",
  "model": "res.partner",
  "values_list": [
    {"name": "Partner 1", "email": "[email protected]"},
    {"name": "Partner 2", "email": "[email protected]"}
  ]
}

Decoded result (shape):

{
  "ids": [101, 102],
  "created_count": 2,
  "success": true
}

Claude Desktop config example

Set your MCP server command to the built binary:

Odoo 19+ (API Key):

{
  "mcpServers": {
    "odoo-rust": {
      "command": "/absolute/path/to/odoo-rust-mcp/rust-mcp/target/release/rust-mcp",
      "args": ["--transport", "stdio"],
      "env": {
        "ODOO_INSTANCES": "{\"production\":{\"url\":\"https://mycompany.example.com\",\"db\":\"mycompany\",\"apiKey\":\"YOUR_API_KEY\"}}"
      }
    }
  }
}

Odoo < 19 (Username/Password):

{
  "mcpServers": {
    "odoo-rust": {
      "command": "/absolute/path/to/odoo-rust-mcp/rust-mcp/target/release/rust-mcp",
      "args": ["--transport", "stdio"],
      "env": {
        "ODOO_INSTANCES": "{\"legacy\":{\"url\":\"https://mycompany.example.com\",\"db\":\"mycompany\",\"version\":\"18\",\"username\":\"admin\",\"password\":\"your_password\"}}"
      }
    }
  }
}

Cursor config example

Cursor supports stdio, SSE, and Streamable HTTP transports. See Cursor docs: cursor.com/docs/context/mcp.

Cursor (recommended): stdio

Put this in ~/.cursor/mcp.json (or ${workspaceFolder}/.cursor/mcp.json):

IMPORTANT: For stdio transport, you must use absolute paths for config files because Cursor runs the binary from a different working directory.

Odoo 19+ (complete example):

{
  "mcpServers": {
    "odoo-rust-mcp": {
      "type": "stdio",
      "command": "/absolute/path/to/odoo-rust-mcp/rust-mcp/target/release/rust-mcp",
      "args": ["--transport", "stdio"],
      "env": {
        "ODOO_URL": "http://localhost:8069",
        "ODOO_DB": "mydb",
        "ODOO_API_KEY": "YOUR_API_KEY",
        "MCP_TOOLS_JSON": "/absolute/path/to/odoo-rust-mcp/config/tools.json",
        "MCP_PROMPTS_JSON": "/absolute/path/to/odoo-rust-mcp/config/prompts.json",
        "MCP_SERVER_JSON": "/absolute/path/to/odoo-rust-mcp/config/server.json"
      }
    }
  }
}

Odoo < 19 (complete example):

{
  "mcpServers": {
    "odoo-rust-mcp": {
      "type": "stdio",
      "command": "/absolute/path/to/odoo-rust-mcp/rust-mcp/target/release/rust-mcp",
      "args": ["--transport", "stdio"],
      "env": {
        "ODOO_URL": "http://localhost:8069",
        "ODOO_DB": "mydb",
        "ODOO_VERSION": "18",
        "ODOO_USERNAME": "admin",
        "ODOO_PASSWORD": "admin",
        "MCP_TOOLS_JSON": "/absolute/path/to/odoo-rust-mcp/config/tools.json",
        "MCP_PROMPTS_JSON": "/absolute/path/to/odoo-rust-mcp/config/prompts.json",
        "MCP_SERVER_JSON": "/absolute/path/to/odoo-rust-mcp/config/server.json"
      }
    }
  }
}

Using .env file:

{
  "mcpServers": {
    "odoo-rust-mcp": {
      "type": "stdio",
      "command": "/absolute/path/to/odoo-rust-mcp/rust-mcp/target/release/rust-mcp",
      "args": ["--transport", "stdio"],
      "envFile": "/absolute/path/to/odoo-rust-mcp/.env"
    }
  }
}

Note: When using envFile, ensure your .env contains absolute paths for MCP_TOOLS_JSON, MCP_PROMPTS_JSON, and MCP_SERVER_JSON.

Cursor: Streamable HTTP (remote / multi-user)

Run the server with --transport http and set:

{
  "mcpServers": {
    "odoo-rust-mcp": {
      "url": "http://127.0.0.1:8787/mcp"
    }
  }
}

With Bearer Token Authentication:

If you have MCP_AUTH_TOKEN set on the server, configure Cursor with the token in headers:

{
  "mcpServers": {
    "odoo-rust-mcp": {
      "url": "http://127.0.0.1:8787/mcp",
      "headers": {
        "Authorization": "Bearer your-secure-random-token-here"
      }
    }
  }
}

Note: Generate a secure token with openssl rand -hex 32 and set MCP_AUTH_TOKEN on the server.

Test / smoke

Run unit tests (no warnings):

cd rust-mcp
RUSTFLAGS='-Dwarnings' cargo test

There is also a small WS smoke client that can validate end-to-end MCP calls (connect → initialize → list tools → call a few tools):

cd rust-mcp
cargo run --release --bin ws_smoke_client -- \
  --url ws://127.0.0.1:8787 \
  --instance default \
  --model res.partner

Example output (local run against res.partner):

tools/list: 11 tools
- odoo_search
- odoo_search_read
- odoo_read
- odoo_create
- odoo_update
- odoo_delete
- odoo_execute
- odoo_count
- odoo_workflow_action
- odoo_generate_report
- odoo_get_model_metadata
odoo_count result: {"count":18}
odoo_search_read count: 2
odoo_search_read sample records: [{"id":46,"name":"Kasir C"},{"id":45,"name":"Kasir B"}]
prompts/list: odoo_common_models, odoo_domain_filters

Security

  • Do not commit .env or any file containing API keys/passwords.
  • Prefer using dedicated bot users with minimal access rights in Odoo for automation.

Release Process

Untuk membuat release baru, ada 2 file yang harus di-update versinya:

  1. rust-mcp/Cargo.toml - field version
  2. config-ui/package.json - field version

Quick Release (Recommended)

Gunakan script helper yang sudah disediakan:

# Bump version, commit, push, dan create tag sekaligus
./scripts/release.sh 0.3.15

Script ini akan:

  • Update version di Cargo.toml dan package.json
  • Commit perubahan
  • Push ke remote
  • Create dan push git tag (yang akan trigger GitHub Actions release workflow)

Manual Release

Jika ingin manual:

# 1. Update version di 2 file
# Edit rust-mcp/Cargo.toml: version = "0.3.15"
# Edit config-ui/package.json: "version": "0.3.15"

# 2. Commit dan push
git add rust-mcp/Cargo.toml config-ui/package.json
git commit -m "chore: bump version to 0.3.15"
git push

# 3. Create dan push tag (akan trigger GitHub Actions)
git tag v0.3.15
git push origin v0.3.15

GitHub Actions akan otomatis:

  • Build binaries untuk semua platform (Linux, macOS, Windows)
  • Build Docker image
  • Build Debian package
  • Create GitHub release dengan artifacts
  • Update Homebrew formula
  • Update APT repository

Monitor progress: https://github.com/rachmataditiya/odoo-rust-mcp/actions

Yorumlar (0)

Sonuc bulunamadi