odoo-rust-mcp
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)
- Multi-instance support via
ODOO_INSTANCES - 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)
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:
dbis optional for Odoo 19+ (only needed when Host header isn't enough to select DB).dbis required for Odoo < 19 (legacy mode).versiondetermines authentication mode:< 19uses username/password,>= 19uses API key.- Extra fields in the JSON are ignored.
- If an instance omits
apiKey, the server will fall back to the globalODOO_API_KEY(if set). - If an instance omits
username/password, the server will fall back toODOO_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.jsondefines:- 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)
- tool
prompts.jsondefines promptname/description/contentserver.jsondefines 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.jsonrust-mcp/config/prompts.jsonrust-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"
Sample files are provided in:
rust-mcp/config/tools.jsonrust-mcp/config/prompts.jsonrust-mcp/config/server.json
Seed defaults (used only when files are missing):
rust-mcp/config-defaults/tools.jsonrust-mcp/config-defaults/prompts.jsonrust-mcp/config-defaults/server.json
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
envtemplate file - Loads environment variables from
~/.config/odoo-rust-mcp/env - Sets default MCP config paths from Homebrew share directory
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(orrust-mcp.exeon Windows) - the binaryconfig/- default configuration files (tools.json, prompts.json, server.json).env.example- example environment variablesinstall.sh(Linux/macOS) orinstall.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 withPOST /messages)
Authentication (HTTP Transport)
The HTTP transport supports Bearer token authentication as per the MCP specification.
Enable authentication:
export MCP_AUTH_TOKEN=your-secure-random-token-here
When 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"}}'
Notes:
- If
MCP_AUTH_TOKENis 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
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-networkfor integration with other containers (n8n, dify, etc.) - Health check for container orchestration
- Volume mounts for config files
- Support for
ODOO_INSTANCES_JSONfor multi-instance setup - Resource limits and labels for service discovery
Multi-instance configuration:
- Create
instances.jsonwith your Odoo instances:
{
"production": {"url": "https://odoo.example.com", "db": "prod", "apiKey": "xxx"},
"staging": {"url": "https://staging.example.com", "db": "staging", "apiKey": "yyy"}
}
- Mount and configure in
.env:
ODOO_INSTANCES_JSON=/config/instances.json
- 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:
- Always set
mcp.authTokenfor HTTP authentication - Use external secrets (Vault, AWS Secrets Manager) instead of storing credentials in values.yaml
- Enable pod disruption budgets for zero-downtime updates
- Configure resource limits based on your workload
- 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_deleteodoo_execute,odoo_count,odoo_workflow_action,odoo_generate_report,odoo_get_model_metadata- cleanup tools (
odoo_database_cleanup,odoo_deep_cleanup) guarded byODOO_ENABLE_CLEANUP_TOOLS=true
Supported op.type values (used in tools.json):
search,search_read,read,create,write,unlinksearch_count,workflow_action,executegenerate_report,get_model_metadatadatabase_cleanup,deep_cleanup
Prompts
Prompts are defined by prompts.json (authoritative). The default seed includes:
odoo_common_modelsodoo_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": "demo@acme.test"
}
}
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]
}
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
.envor any file containing API keys/passwords. - Prefer using dedicated bot users with minimal access rights in Odoo for automation.