Skip to content

keboola/odoo-mcp

Repository files navigation

Odoo MCP Server

A Model Context Protocol (MCP) server that lets AI assistants like Claude securely interact with an Odoo 18 ERP instance — with per-user OAuth 2.1 identity, employee self-service workflows, generic record CRUD, and optional document signing.

Why this server?

Several Odoo MCP servers already exist (Odoo's own mcp_server addon, MuK MCP, and community XML-RPC bridges such as ivnvxd/mcp-server-odoo). Most of them are generic CRUD bridges that act with a single shared admin credential.

This server is different — it is built around authenticated end users:

  • OAuth 2.1 + PKCE with a per-request bearer token; each request is mapped to the calling user's Odoo employee record.
  • Employee self-service tools — your own profile, manager, team, leave balance/requests, public holidays, and HR documents — all automatically scoped to the authenticated user, never to arbitrary records.
  • Granular OAuth scopes per tool (odoo.read, odoo.hr.profile, odoo.leave.write, …) instead of all-or-nothing access.
  • Generic CRUD tools are still available for admin/integration scopes.

If you want a per-user, HR-focused, auth-first server, this is for you. If you just need an admin-credential CRUD bridge, the community servers above are simpler.

Features

  • OAuth 2.1 / PKCE authentication (Google as the identity provider out of the box; pluggable via OAUTH_PROVIDER=custom).
  • 30 MCP tools: 7 generic CRUD, 16 employee self-service, 7 optional signing.
  • Two transports: streamable HTTP (remote MCP) and stdio (local clients).
  • Per-user scoping: employee identity is derived from the OAuth token, never from tool input.
  • Configurable for any Odoo: custom employee fields, document folders, and the optional signing module are all opt-in via environment variables.
  • Production ready: Docker image, CI, and a reference Cloud Run deployment.

Quick Start

Prerequisites

  • Python 3.12+
  • An Odoo 18 instance and an API key (or username/password)
  • A Google OAuth client (for production auth) — or run with OAUTH_DEV_MODE=true locally

Installation

git clone https://github.com/OWNER/odoo-mcp-server.git
cd odoo-mcp-server

python -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"

Configuration

Copy .env.example to .env and fill in your values. Minimum to start:

ODOO_URL=https://your-odoo-instance.example.com
ODOO_DB=your-database-name
ODOO_API_KEY=your_api_key_here

# OAuth (production). For local dev you can instead set OAUTH_DEV_MODE=true.
OAUTH_PROVIDER=google
OAUTH_CLIENT_ID=your-google-client-id.apps.googleusercontent.com
OAUTH_CLIENT_SECRET=your_client_secret_here
OAUTH_RESOURCE_IDENTIFIER=https://your-mcp-server.example.com
OAUTH_REDIRECT_URI=https://your-mcp-server.example.com/oauth/callback

Required settings are validated at startup — the server fails fast with a clear message if any are missing (no silent defaults).

Running the Server

# HTTP server (remote MCP / Claude.ai connector)
python -m odoo_mcp_server.http_server

# stdio (local MCP clients such as Claude Desktop)
python -m odoo_mcp_server.server

Available Tools

Generic CRUD (scopes: odoo.read / odoo.write)

Tool Description
search_records Search records with domain filters
get_record Get a single record by ID
create_record Create a new record
update_record Update an existing record
delete_record Delete a record
count_records Count records matching a domain
list_models List available Odoo models

Employee self-service (HR / leave / document scopes)

Profile & org: get_my_profile, get_my_manager, get_my_team, find_colleague, get_direct_reports, update_my_contact. Leave: get_my_leave_balance, get_my_leave_requests, request_leave, cancel_leave_request, get_public_holidays. Documents: get_my_documents, get_document_categories, upload_identity_document, download_document, get_document_details.

All of these are automatically restricted to the authenticated user's own data.

Document signing — optional (scopes: odoo.sign.*)

Disabled by default. Requires the community OCA sign_oca addon (sign.oca.* models, not Odoo Enterprise Sign). Enable with SIGN_MODULE_ENABLED=true to expose: get_my_pending_signatures, get_my_signature_requests, get_signature_request_status, list_sign_templates, send_signature_request, download_signed_document, cancel_signature_request.

Optional Features

These default to stock-Odoo-safe values, so the server works against a vanilla Odoo with no extra configuration.

Setting Purpose
ENABLED_TOOL_GROUPS Comma-separated tool groups to expose: crud, employee (default crud,employee). Use crud for a generic admin bridge or employee for self-service only.
EMPLOYEE_CUSTOM_FIELDS JSON map of output key → custom hr.employee field, e.g. {"preferred_name":"x_preferred_name","division":"x_division"}. Surfaced on get_my_profile.
DMS_ALLOWED_FOLDERS / DMS_RESTRICTED_FOLDERS Comma-separated document folder names employees may see vs. must never see.
SIGN_MODULE_ENABLED Expose the OCA Sign tools (requires the sign_oca addon).
INTERNAL_EMAIL_DOMAIN Users whose email matches this domain receive extended write scopes.
YOLO_MODE read = no-auth read-only (only read tools exposed); true = no-auth full access. For trusted/local use only.

Deployment modes

The server runs anywhere from a single trusted-network Odoo with no auth, to a multi-user, multi-environment OAuth deployment. See docs/DEPLOYMENT.md for copy-paste recipes (no-auth/read-only, single-identity API key, Google OAuth, custom OIDC, stdio) and how to pick tool groups.

Claude Desktop Integration

{
  "mcpServers": {
    "odoo": {
      "url": "https://your-deployment-url/mcp",
      "transport": "streamable-http"
    }
  }
}

See docs/CLAUDE_INTEGRATION.md for the full Claude.ai connector setup (Google OAuth redirect URIs, scopes, etc.).

Testing

pytest tests/unit          # fast, no external services
pytest tests/integration   # requires a real Odoo (skips without credentials)
pytest --cov=src/ --cov-report=html

Unit tests run out of the box — conftest.py provides placeholder Odoo settings so nothing external is needed.

Deployment

Docker

docker build -t odoo-mcp-server -f docker/Dockerfile .
docker run -p 8080:8080 \
  -e ODOO_URL=https://your-odoo-instance.example.com \
  -e ODOO_DB=your-database-name \
  -e ODOO_API_KEY=your_key \
  odoo-mcp-server

Google Cloud Run

A reference Cloud Run deployment is wired into .github/workflows/ci.yml. Set the GCP_REGION repository variable and the secrets listed in docs/CI_CD.md, then merge to main.

Project Structure

odoo-mcp-server/
├── src/odoo_mcp_server/
│   ├── server.py          # stdio MCP entry point
│   ├── http_server.py     # HTTP transport + OAuth flow
│   ├── config.py          # settings, scopes, rate limits
│   ├── oauth/             # OAuth 2.1 resource server, token validation
│   ├── odoo/              # Odoo XML-RPC client
│   ├── tools/             # MCP tools (records, employee, sign)
│   └── resources/         # MCP resources (model discovery)
├── tests/                 # unit / integration / e2e
├── docker/                # Docker configuration
├── terraform/             # optional AI/security reviewer infrastructure
└── docs/                  # security, CI/CD, Claude integration

Security

  • OAuth 2.1 with PKCE for all authentication flows
  • JWT validation against the provider's JWKS
  • Employee identity derived from the token, never from user input
  • All employee queries constrained to the authenticated user
  • Credentials loaded from the environment only — never hardcoded

Report vulnerabilities via SECURITY.md. See docs/SECURITY.md for the security model.

Contributing

Contributions are welcome — see CONTRIBUTING.md.

License

MIT

About

OAuth 2.1 MCP server for Odoo ERP: per-user identity, employee self-service, and document signing

Resources

License

Contributing

Security policy

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages