Odoo MCP server
Provides tools for interacting with a self-hosted Odoo instance, including listing and describing models, searching and reading records, aggregating data, and creating, updating, or deleting records via Odoo's XML-RPC API.
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 servershow me the 10 most recent sales orders"
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 server
A Model Context Protocol server that talks to one or two Odoo instances
over the standard XML-RPC external API. Tools are built on live
introspection (ir.model, fields_get, read_group) rather than one
hardcoded tool per module, so newly installed apps — including custom ones —
show up automatically.
One or two instances
The nine tools below (context, list_models, describe_model,
search_read, read_records, aggregate, create_record,
update_record, delete_record) always target the initial instance,
configured by the unprefixed ODOO_* variables — unchanged from the single
-instance version of this server, so an existing deployment needs no
reconfiguration.
A second, transfer, instance can be added by setting a second set of
variables prefixed ODOO_TRANSFER_* (see below). Doing so registers a
second copy of the same nine tools, each named transfer_<name> (e.g.
transfer_search_read), pointed at that instance instead. If
ODOO_TRANSFER_URL isn't set, none of the transfer_* tools are
registered at all — the server behaves exactly as a single-instance one.
Write and delete are gated per instance, independently:
MCP_ENABLE_WRITE / MCP_ENABLE_DELETE govern the initial instance's
tools; MCP_ENABLE_TRANSFER_WRITE / MCP_ENABLE_TRANSFER_DELETE govern
the transfer instance's — enabling bulk write/delete against a transfer
instance (e.g. to wipe and re-populate it) never touches, or implies
anything about, the initial instance's own posture.
Related MCP server: mcp-server-odoo
Tools and permission tiers
Every tool carries standard MCP annotations (readOnlyHint, destructiveHint,
idempotentHint) so an MCP client can offer real per-tool consent —
"always allow", "ask every time", or "never" — rather than one blanket
switch for the whole server. In Claude, this is what populates the
per-tool permission controls in the connector's settings.
Tool | Tier |
|
| Server-side failsafe |
| Read | true | false | always on |
| Read | true | false | always on |
| Read | true | false | always on |
| Read | true | false | always on |
| Read | true | false | always on |
| Read | true | false | always on |
| Write | false | false |
|
| Write | false | true |
|
| Delete | false | true |
|
Two layers of consent, both have to agree. The server-side env vars
(MCP_ENABLE_WRITE, MCP_ENABLE_DELETE) are an infrastructure failsafe —
they exist so a leaked API key or a careless client can't silently mutate
or delete data on a server nobody meant to expose that way. The primary
permission surface is meant to be your MCP client's own per-tool controls,
driven by the annotations above. Set the client side the way you actually
want to work day to day (e.g. reads always allowed, writes ask every time,
delete never) — the server flags are the backstop underneath that, not a
replacement for it.
update_record is flagged destructiveHint: true even though it's
technically an update, not a delete — it overwrites existing field values
in place with no undo, which is the same risk profile MCP's spec treats as
destructive.
Required environment variables
Initial instance (always required)
Variable | Example | Notes |
|
| No trailing slash needed |
|
| The database name you created |
|
| The login, not the display name |
| (generated in Odoo) | Preferred over a raw password — see below |
| — | Only used if |
|
| Gates |
|
| Gates |
Transfer instance (optional — set all four _URL/_DB/_USERNAME and
either _API_KEY or _PASSWORD together, or leave all unset)
Variable | Notes |
| Setting this is what makes the |
| |
| |
| Preferred over a raw password |
| Only used if |
|
|
|
|
Either instance
Variable | Notes |
| Set automatically by Railway — don't set manually there |
Generating an API key instead of using the admin password
In Odoo: click your avatar (top right) → My Profile → Account
Security tab → New API Key. Use that value for ODOO_API_KEY. This
avoids putting the actual login password in an environment variable, and
lets you revoke MCP access later without changing the admin password.
Running locally
pip install -r requirements.txt
export ODOO_URL=https://odoo-production-2cb7.up.railway.app
export ODOO_DB=chaldea_mcp
export ODOO_USERNAME=admin
export ODOO_API_KEY=your-key-here
python server.pyServer listens on http://localhost:8000 (streamable HTTP transport).
Deploying to Railway (same project as Odoo)
This isn't a Docker-image deploy like the Odoo/Postgres services — it needs to build from this source, so it goes in via a GitHub repo:
Push this folder to a new GitHub repo (or a subfolder of an existing one).
In the
odoo-mcp-hackathonRailway project, add a new service from that GitHub repo.Set the environment variables above on that service. For
ODOO_URL, use the Odoo service's Railway-generated public domain — or, since both services live in the same project, you can reference it privately once the MCP server also needs to resolve container-to-container (ask before assuming that's wired correctly; XML-RPC over the private network works the same as the public URL, just faster and without leaving Railway).Generate a public domain for the MCP service once it deploys successfully, so an MCP client (Claude, or anything else) can reach it.
Connecting a client
Point an MCP-compatible client at the deployed service's
/mcp endpoint (streamable HTTP transport). Exact connection syntax
depends on the client — for Claude specifically, this is added as a custom
connector using the service's URL.
A note on the mcp package version
This code targets mcp>=2.0, which renamed FastMCP to MCPServer
(mcp.server.mcpserver.MCPServer) and changed how the HTTP transport is
started. Verified against mcp==2.1.1 — all 8 tools import and register
correctly with proper JSON schemas generated from the type hints.
If you're following an older tutorial that references FastMCP or
mcp.server.fastmcp, that's the pre-2.0 API and won't match this code.
The Python MCP SDK moves fast; if a future version changes this again, run
pip show mcp and check
https://github.com/modelcontextprotocol/python-sdk for the current
run_streamable_http_async signature.
This server cannot be deployed
Maintenance
Related MCP Connectors
Hosted MCP server for AI-driven data ops. Create apps, manage schemas, and CRUD structured data.
Build multi-tenant apps over MCP. Schemas, CRUD, deploys — access control enforced server-side.
Unified MCP Server is a remote MCP connector for AI agents and vertical AI products that provides access to 22,000+ authorized SaaS tools across 400+ integrations and 24 categories directly inside LLMs (Claude, GPT, Gemini, Cohere). Tools operate only on explicitly authorized customer connections, enabling agents to safely read and write against live third-party systems.
Let AI agents query data and act across all your business apps via MCP.
Related MCP Servers
- AlicenseNot gradedqualityCmaintenanceEnables interaction with Odoo ERP systems for product, customer, order, invoice, and payment management using MCP tools.6MIT
- AlicenseNot gradedqualityCmaintenanceEnables interaction with Odoo ERP through MCP, including an additional sql_query tool for custom queries.Mozilla Public 2.0
- AlicenseNot gradedqualityCmaintenanceEnables Claude to interact with Odoo through 12 MCP tools covering discovery, CRUD operations, and bulk import/export via XML-RPC.MIT
- FlicenseNot gradedqualityBmaintenanceEnables interacting with Odoo ERP through a stateless HTTP MCP server, providing CRUD and execution tools via JSON-RPC.-