Odoo Projects MCP
Provides a role-controlled interface to Odoo projects, tasks, and website pages, enabling search/read, create/update projects and tasks, edit page content, and publish/unpublish pages through Odoo's JSON-2 API.
This server does not currently have a deployable release on Glama. Follow the repository's setup instructions to install and configure it for your MCP client, including any required credentials and local dependencies.
Odoo Projects MCP
An independently deployable MCP server that gives AI clients and workflow tools a narrow, role-controlled interface to Odoo projects, tasks, website pages, and blog posts.
Portfolio project: demonstrates integration planning, API discovery, scoped tool design, role-based access, Docker deployment, and security trade-off documentation. It is a prototype and has not been independently audited or certified for regulatory compliance.
The problem
Business teams want to use AI assistants and automation with the project and website data already held in Odoo. Giving an AI client generic database or model access would be too broad. This service exposes named operations with explicit inputs and field allowlists, while Odoo's own permissions remain in force.
Related MCP server: MCP Server for Odoo
Architecture
flowchart LR
AI[AI client] -->|Streamable HTTP + bearer token| MCP[MCP server]
WF[Workflow client] -->|Streamable HTTP + bearer token| MCP
MCP -->|Named tools, role checks| ODOO[Selected Odoo instance]
MCP -->|Odoo JSON-2 over HTTPS| ODOO
ADMIN[Local access admin page] -->|Admin role required| USERS[(SQLite user directory)]The operator selects a configured Odoo instance on each tool call. The server does not expose arbitrary SQL or a generic model-call tool. Odoo API credentials stay on the server.
Current capabilities
Search and read projects and tasks.
Create and update projects and tasks with validated fields, including task assignees; move tasks between project stages and allowed states; archive and restore tasks and projects.
Search and read website pages, update page content, and publish or unpublish with separate tools.
List websites and blogs; search, read, create, and edit blog posts with explicit website targeting.
create_blog_postandupdate_blog_postwrite in the Odoo connection user's language, which must be the website's primary language. To translate a post, create it in the primary language, callget_blog_post_translation_terms, then send the returned term map ascontent_termstoset_blog_post_translation; this updates HTML terms without replacing the primary content. Editors can attach public cover images; schedulers can set a future publication time. Blog creation always starts unpublished, and publish/unpublish use separate tools and roles.create_blog_postandupdate_blog_postacceptcontent_format:html(default, content stored as given) ormarked_text.set_blog_post_translationacceptscontent_marked_textas an alternative tocontent_terms. See Marked text format.update_blogrenames a blog or changes its subtitle in one active website language (langis required). Renaming changes the blog's URL slug.get_blog_postreturnscover_image_url, the absolute URL of the post's cover image (ornull), so a client can reuse it aswebsite_meta_og_img.create_blog_postandupdate_blog_postaccept an optionallang(Odoo code such asen_US). It must be the website's primary language, otherwise the call fails without writing; the post is then written in that language whatever the Odoo user's language is. Clients use it to check that their original text is in the language Odoo expects before adding translations.Until its scheduled date, Odoo hides a post only from the blog list; its URL,
/feed, and/sitemap.xmlalready show it.Scheduling also sends Odoo's new-post notification to blog followers immediately.
Authenticate MCP users with bearer tokens and grant permissions through named roles.
Manage Odoo connections, users, roles, token rotation, and revocation in a local admin page.
Connect to Odoo 19+ through JSON-2 or Odoo 18 through XML-RPC over HTTPS.
Marked text format
The content generator saves long-form posts to a Google Doc as marked text, which a person reviews before a client publishes it through this server. The conversion to HTML is a fixed rule implemented once, in odoo_mcp/marked_text.py:
Marked text | HTML |
| Post |
|
|
Lines starting with |
|
Lines starting with |
|
Other lines |
|
Bare |
|
Before converting, trailing spaces, repeated blank lines, and the Google Docs escapes \_ \# \* \[ \] are cleaned, and &, < and > are escaped. The output has no classes or styles, and no content is added or removed: hashtags, calls to action, and similar decisions belong to the generator or the reviewer.
For a translation, pass the translated marked text with the same structure as the primary-language text as content_marked_text. Its blocks are paired by position with the post's Odoo translation terms. Odoo translates each link separately from the text before and after it (bold and italics stay inside the term), so each block must also keep the same links. A marked-text link's text is its URL, so a source link with descriptive text, such as «CEPAL press release», is translated with the URL; use content_terms to translate such link texts. If the number or type of blocks or links differs, or the post contains terms outside its text blocks, the call fails without writing anything; use content_terms for such posts. A translated H1 line becomes that language's name unless name is passed.
Security model and current limits
MCP roles restrict tool access and each user can be restricted to named Odoo instances; Odoo permissions and record rules provide a second authorization layer.
The Odoo instance name is selected explicitly, and the configured URL must use HTTPS.
The default Compose binding is
127.0.0.1; this is a local development setup, not a public deployment recipe.Existing SQLite users keep all-instance access during schema migration to preserve current behavior. A
*scope also grants access to instances added later; review and narrow user scopes as needed.The admin page can add, edit, test, deactivate, and reactivate Odoo targets. API keys are kept in
mcp-state/odoo-instances.jsonoutside the source tree with restrictive file permissions; they are not encrypted by the application.Tokens are static bearer tokens. There is no OAuth/OIDC flow, rate limiting, or production audit trail yet.
The same configured Odoo technical account is used for calls to a target, so Odoo does not attribute each MCP action to a distinct human user.
The admin page is intended for local use. Remote use requires a deliberate identity, HTTPS, session, and deployment security design.
No GDPR, AI Act, NIS2, or other compliance certification or conclusion is claimed. Applicability and controls depend on the deployment, data, purpose, and parties involved.
See Architecture, Threat model, and Data protection notes for assumptions and open work.
Run locally
Requirements: Docker Compose and an Odoo instance with an enabled external API.
Set up Compose configuration and a private connection directory. For the local default:
cp compose.env.example .env mkdir -p local cp .env.example local/.env cp odoo-instances.example.json local/odoo-instances.json cp mcp-users.example.json local/mcp-users.jsonSet an Odoo API key and unique random MCP tokens of at least 32 characters in
local/.env. Set the initial URL and API-key environment variable name inlocal/odoo-instances.json. Inlocal/mcp-users.json, grant each user only the configured instance names they need;*means all current and future instances.Start the service:
docker compose up -d --build
The MCP endpoint is http://127.0.0.1:8000/mcp; the local admin page is http://127.0.0.1:8000/admin. The configured owner token is used to sign in. User tokens are shown once when created or rotated. Add later Odoo targets from the Odoo instances section; a successful authenticated read is required before creating or editing a connection, and the server repeats the check so a direct API request cannot bypass it. Removing a key is allowed only after deactivating that instance; an instance without a key cannot be reactivated. Local config, instance credentials, SQLite state, and .env files are outside Git and the Docker build context.
Choose JSON-2 for Odoo 19+ or XML-RPC for Odoo 18 connections in the admin page. XML-RPC needs the database name, Odoo username/login, and an API key (used as the API password); JSON-2 uses an API key and an optional database name. Odoo 18's external API availability depends on the Odoo subscription plan.
When upgrading an existing SQLite user database, the schema adds the instance allowlist while preserving existing access as *. After starting the upgraded service, use the admin page to replace * with explicit instance names for each account before configuring additional Odoo targets.
To keep configuration outside the repository, set MCP_CONNECTIONS_DIR in the ignored project-root .env to the private configuration directory. Keep the API key and initial user tokens in that private directory's .env. On first startup, the service copies the bootstrap instance settings into mcp-state/odoo-instances.json; later API key changes are made in the admin page. Restrict access to this directory and back it up securely. The Compose file defaults to ./local for a fresh clone.
Roles
Role | Tools |
| Connection check and project, task, and page search/read; archived records can be included in searches |
| Create and update tasks; list project stages and change task stage/state |
| Archive and restore tasks |
| Search, read, create, update, archive, and restore projects; list task stages |
| Edit page content |
| Publish and unpublish pages |
| List websites and blogs; rename blogs per language; search, read, create, edit, and translate blog posts |
| List websites and blogs; search, read, publish, and unpublish blog posts |
| Schedule blog posts for a future date |
| All currently registered tools and user administration |
Roles can be combined for a user. Instance access is configured separately per user. New users in the admin page must receive explicit active instance names; use * only when they need every current and future instance.
Archiving a project also archives all its tasks. Restoring the project restores all its tasks too, including tasks that were already archived individually before the project was archived.
Development
Run the unit suite in Docker:
docker build -f Dockerfile.test -t odoo-projects-mcp-test .
docker run --rm odoo-projects-mcp-testAn opt-in, read-only version probe is available by setting ODOO_TEST_BASE_URL for the test container. It checks /web/version; it does not validate authenticated reads, writes, or tenant isolation. These are documented validation gaps.
Project status
The prototype has been exercised against an Odoo 19 Community test instance. The authenticated Odoo operations, multi-instance isolation, remote identity, audit retention, and production deployment controls still need a repeatable verification plan before production use.
The project plan and decisions are in claude.md. The next engineering priorities are repeatable authorization checks, security/audit controls, and automated CI checks.
License
This project is licensed under LGPL-3.0. The license was chosen to align with Odoo Community's license; this connector is a separate project and does not contain Odoo source code. See LICENSE.
This server cannot be deployed
Maintenance
Related MCP Connectors
Read, write and run Odoo actions from any AI app, as each user, with approval rules per colleague.
Odoo ERP for AI agents: hosted OAuth endpoint, gated writes, one endpoint for every instance.
Task management for people and AI agents, with scoped OAuth access to issues, projects, and docs.
Task management for people and AI agents, with scoped OAuth access to issues, projects, and docs.
Related MCP Servers
- 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
- FlicenseNot gradedqualityCmaintenanceEnables AI assistants to securely access and interact with Odoo data through natural language, supporting full CRUD operations, OAuth 2.1 and API key authentication, and granular per-model permissions.-
- FlicenseNot gradedqualityCmaintenanceEnables AI assistants to securely connect to Odoo and perform CRUD operations, custom tool calls, and data queries through natural language, with OAuth 2.1 and API key authentication.-
- FlicenseNot gradedqualityBmaintenanceEnables AI assistants to securely access and interact with Odoo data through natural language, supporting CRUD operations, attachments, and role-based permissions.-