Odoo MCP Bridge
Provides tools to interact with Odoo's external API, enabling listing models, describing models, searching, aggregating, creating, updating, deleting records, and calling business methods, with configurable permission boundaries and field masking.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Odoo MCP BridgeList the 5 most recent confirmed sale orders with their total amounts."
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Odoo MCP Bridge
An MCP server that sits outside Odoo and reaches it over the external API. Nothing is installed in the database, so it works on Odoo Online, where custom modules are impossible, as well as on Odoo.sh and on-premise.
One HTTPS endpoint, POST /mcp, stateless Streamable HTTP. Eight tools:
odoo_list_models, odoo_describe_model, odoo_search, odoo_aggregate,
odoo_create, odoo_update, odoo_delete, odoo_call_method.
Claude / ChatGPT ──HTTPS + bearer──▶ this bridge ──HTTPS + API key──▶ Odoo
(your host) (Online / .sh)Read this before deploying anything
The bridge holds an Odoo API key, and an API key carries every right its
user has. The permission matrix in config.yaml runs in this process, in
front of that key. It stops an assistant from doing something unintended. It
does not stop anyone who obtains the key.
So the matrix is the second line, not the first. The first line is the Odoo side:
Create a dedicated user —
mcp.bot@company.com— not a person's account.Give it the narrowest groups that let it do the job. Never Settings.
Write record rules on that user for anything sensitive.
Clear its password so the account cannot be used to log in at all; the API key becomes the only way in.
Generate the key: Preferences → Account Security → New API Key.
Whatever survives that is what the bridge is working with. Sell it that way, and the matrix on top is a genuine extra rather than a claim that collapses the first time someone looks at it.
Related MCP server: MCP Server for Odoo
Quick start
git clone <your repo> && cd odoo-mcp-bridge
pip install -r requirements.txt
cp config.example.yaml config.yaml # then edit it
export MCP_TOKEN_DEMO=$(python -c "import secrets;print(secrets.token_urlsafe(32))")
export ODOO_API_KEY_DEMO=<the key from Odoo>
export MCP_CONFIG=config.yaml
uvicorn app.main:app --reload --port 8000Check that Odoo actually answers:
curl localhost:8000/readyzThen call a tool by hand before pointing an assistant at it:
curl -s localhost:8000/mcp \
-H "Authorization: Bearer $MCP_TOKEN_DEMO" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call",
"params":{"name":"odoo_list_models","arguments":{}}}' | jqTests:
pip install pytest && pytest -qConnecting an assistant
The endpoint is https://<your-host>/mcp with an
Authorization: Bearer <the token from config.yaml> header. Anything that
speaks remote MCP with a custom header will connect — Claude's custom
connectors, Claude Code (claude mcp add --transport http odoo <url> --header ...),
and the ChatGPT developer-mode connector among them.
Two tokens are involved and they are easy to confuse:
Token | Who holds it | What it proves |
| the assistant | may talk to this bridge, as this tenant |
| this bridge | may talk to that Odoo database, as the bot user |
Never give the second one to an assistant.
Configuration
config.example.yaml is the reference; it is commented as documentation.
The shape:
tenants:
- id: acme
token: env:MCP_TOKEN_ACME
read_only: true # a good place to start
odoo:
url: https://acme.odoo.com
db: acme
transport: json2 # Odoo 19+. Use xmlrpc for 17/18.
api_key: env:ODOO_API_KEY_ACME
models:
sale.order:
read: true
write: false
domain: [["state", "not in", ["draft"]]] # applied to reads AND writes
methods: [action_confirm] # ORM verbs are refused here
fields_deny: [margin]Every secret is env:NAME. Nothing sensitive goes in the file, so the file
belongs in git and the secrets belong in the platform's secret store.
Design points worth knowing:
A model not listed does not exist. No defaults, no inheritance.
domainis a boundary, not a filter. It is ANDed into every read and every id is resolved through it before any write, delete or method call. A caller holding an id from elsewhere still cannot touch a record the domain excludes.The AND is explicit. Concatenating a caller's domain onto a policy domain is unsafe: a caller who sends
["|", leaf]turns the join into an OR and the policy stops applying. Domains are validated for balance and joined with an explicit&. There is a test for exactly this.ORM verbs cannot be whitelisted as methods.
write,unlink,copyand friends are refused at config-load time, so the matrix stays the only way to change data.A business method needs
write. Notread. A model marked read-only cannot confirm an order.Deleting needs
confirm: trueas a separate acknowledgement.Field masking (
fields_deny/fields_allow) applies to reading, writing, describing, grouping and aggregating — not just to the row output.
Transports
Odoo version |
| Notes |
19+ |
|
|
17, 18 |
| also needs |
XML-RPC and JSON-RPC are deprecated as of Odoo 19 with removal announced for
20, so json2 is where new work should go.
Two consequences of JSON-2 shape what this bridge can offer. Each call is its
own SQL transaction, so nothing here can make two calls atomic — anything
needing atomicity has to be one business method on the Odoo side, which is
why odoo_call_method exists. And on Odoo Online, the external API is
documented as available on Custom plans only, not One App Free or
Standard. Confirm the client's plan before promising anything.
The audit trail
One JSON object per line, on stdout and optionally to a file: who, which tool, which model, which records, how long, and the arguments with anything password-shaped redacted. Failed authentications are logged too, which is the first thing an auditor asks for.
It is evidence, not proof. A file on a host you control can be edited. If a client needs the stronger claim, chain the entries by carrying each line's SHA-256 into the next and publish the head digest somewhere you cannot reach. Until that exists, do not call it immutable.
Where to host it, free
The bridge is stateless and tiny, which is what makes free hosting realistic at all. Ranked for this specific job.
1. Google Cloud Run — best overall
Perpetual free tier (~2M requests/month), scales to zero, cold starts around a second, real HTTPS, secrets in Secret Manager. Needs a billing account on file, which is the only catch, and at this traffic the bill stays at zero.
gcloud run deploy odoo-mcp --source . --region us-central1 \
--allow-unauthenticated --max-instances 2 \
--set-env-vars MCP_CONFIG=/app/config.yaml \
--set-secrets ODOO_API_KEY_ACME=odoo-key:latest,MCP_TOKEN_ACME=mcp-token:latestUse us-central1: the free allowance is region-dependent. Keep
--max-instances low and set a $1 budget alert — Cloud Run has no hard cap,
it bills. See DEPLOY.md.
2. Oracle Cloud Always Free — best if you want it always on
A genuinely free-forever ARM VM (up to 4 cores / 24 GB). Always on, no cold starts, no request caps. You manage the box and the TLS certificate — Caddy makes that two lines. The right answer for anything a client depends on.
3. Hugging Face Spaces (Docker SDK) — easiest, no card
Free CPU tier, generous RAM, no credit card, secrets under Settings → Variables and secrets. Must listen on 7860, which the Dockerfile already does. Caveats: free Spaces are public and sleep after long inactivity, and it is built for demos rather than business APIs. Fine for testing and demos; do not put a client's production key there.
4. Render — free web service
512 MB, 0.1 vCPU, deploy from GitHub, render.yaml included. The problem for
this use case is that free services spin down after 15 minutes idle and
take up to a minute to wake — and an MCP client will report that as a failed
connection, not as a slow one. Workable only with a pinger hitting /healthz
every 10 minutes, which eats most of the monthly hour allowance.
5. Koyeb — free, scale-to-zero
One free service, 0.1 vCPU / 512 MB. Same cold-start caveat as Render.
No longer free: Heroku and Fly.io. Avoid: PythonAnywhere's free tier — outbound network is restricted to an allowlist, so it cannot reach a client's Odoo domain at all.
The honest version
Free tiers are for your demos and your own testing. The moment a paying client's API key is involved, a €4/month VPS or Cloud Run with a billing account is the responsible choice — not because free hosts are badly run, but because a shared free host with no SLA is a strange place to keep a credential that can read someone's whole database. Free tiers also disappear with a month's notice; two of the ones on every list a year ago are gone.
Whatever you pick, three things are non-negotiable: HTTPS, secrets in the
platform's secret store rather than in the repo, and a long random token:
per tenant.
Roadmap
OAuth 2.1 with PKCE, so each person authorises separately instead of sharing one bearer token
Hash-chained audit entries
outputSchemaon the tool definitionsPer-tool rate limits rather than one bucket per tenant
Licence
Choose one before publishing. If this is going to be sold alongside services, AGPL-3 or a commercial licence; if it is a lead magnet, MIT.
This server cannot be deployed
Maintenance
Related MCP Connectors
- odooOAuthcom.odooconsole
Odoo ERP for AI agents: hosted OAuth endpoint, gated writes, one endpoint for every instance.
Odoo MCP Pack — ERP/CRM via Odoo's external JSON-RPC API.
- Zoxron MCPOAuthcom.zoxron
Your AI agent deploys, migrates & upgrades self-hosted Odoo ERP on a server you own.
- StackOneOAuthcom.stackone
Give AI agents 30,000+ safe, token-optimized actions across Workday, SAP, Oracle + hundreds more.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceEnables AI assistants to interact with Odoo ERP systems through XML-RPC communication. Provides access to Odoo models, records, methods, and data structures for comprehensive ERP integration.2MIT
- AlicenseNot gradedqualityNot gradedmaintenanceEnables AI assistants to interact with Odoo ERP systems through natural language to search records, create entries, update data, and manage business operations. Supports secure authentication and configurable access controls for production environments.Mozilla Public 2.0
- AlicenseNot gradedqualityCmaintenanceEnables AI assistants to interact with Odoo ERP systems through natural language, allowing users to search, create, update, and manage business records like customers, products, and invoices across any Odoo instance.1Mozilla Public 2.0
- AlicenseNot gradedqualityDmaintenanceEnables AI assistants to interact with Odoo databases via XML-RPC and JSON-RPC for performing CRUD operations and managing modules. It supports advanced features like domain-based searching, field metadata inspection, and administrative task execution.5 npmMIT