Odoo Claude MCP
Server Configuration
Describes the environment variables required to run the server.
| Name | Required | Description | Default |
|---|---|---|---|
| ODOO_DB | Yes | Database name | |
| ODOO_URL | Yes | URL of the Odoo instance | |
| ODOO_API_KEY | No | Odoo API key | |
| ODOO_PASSWORD | No | Odoo password | |
| ODOO_USERNAME | Yes | Odoo username | |
| MCP_ADMIN_TOKEN | No | Admin token for MCP gateway |
Capabilities
Features and capabilities supported by this server
| Capability | Details |
|---|---|
| tools | {
"listChanged": false
} |
| completions | {} |
| experimental | {} |
Tools
Functions exposed to the LLM to take actions
| Name | Description |
|---|---|
| odoo_connectA | Add/update an Odoo connection. Auth via password or API key. Protocol: xmlrpc (Odoo 8+) or jsonrpc (Odoo 14+). |
| odoo_cert_infoA | Return the pinned SSL certificate details (issuer, subject, notAfter, fingerprint) for a connection. Useful to verify which self-signed cert MCP has trusted. Requires verify_ssl=False on the connection. |
| odoo_cert_refreshA | Re-fetch the peer SSL certificate for a connection and overwrite the pinned copy. Use after the server's self-signed cert was rotated. Fails if the connection has verify_ssl=True (standard CA verification does not need pinning). |
| odoo_disconnectC | Remove an Odoo connection. |
| odoo_connectionsA | List all configured Odoo connections. |
| odoo_list_modelsC | List available Odoo models (ir.model). Optionally filter by name pattern. |
| odoo_fields_getB | Get field definitions for an Odoo model. Returns field names, types, labels, and attributes. |
| odoo_searchB | Search for record IDs matching a domain filter. |
| odoo_readB | Read specific records by IDs. |
| odoo_search_readC | Search and read records in one call. Most common operation. |
| odoo_search_countC | Count records matching a domain. |
| odoo_createB | Create one or more records. Returns list of new IDs. |
| odoo_writeD | Update existing records. |
| odoo_unlinkC | Delete records by IDs. |
| odoo_executeA | Execute any model method via execute_kw. Use for workflow actions (action_confirm, action_done), custom methods, or anything not covered by CRUD tools. |
| odoo_message_postA | Post a message or internal note on any Odoo record (chatter). Body supports Markdown formatting (headers, bold, italic, tables, code blocks) — automatically converted to HTML. Use message_type='note' for internal notes (employees only) or 'comment' for public messages (visible to followers). |
| odoo_attachment_uploadA | Upload a file as an ir.attachment on an Odoo record. Returns the attachment ID which can be used with odoo_message_post (attachment_ids parameter) or linked to any record. |
| odoo_attachment_downloadA | Download an ir.attachment from Odoo by ID. Returns filename, mimetype, size, and base64-encoded content. |
| odoo_module_infoA | Get detailed information about an Odoo module: Odoo RPC state + filesystem locations (OCA, EE, custom repos). Shows where the module physically exists, its manifest, dependencies, and installation status. |
| odoo_list_translatable_fieldsA | List all translatable fields on an Odoo model. Returns per-field: translate type ('simple' for translate=True, 'html' for html_translate, 'xml' for xml_translate, 'callable' for other), field type, label, help. Use this to discover which fields on blog.post, product.template, website.page, res.partner, etc. can be translated. |
| odoo_get_field_translationsA | Read current translations for a translatable field on a record. For simple translate=True fields returns {lang: value}. For html_translate/xml_translate fields returns {lang: {term: value}}. Auto-detects the translate type via fields_get. Works on blog.post.content, blog.post.name, product.template.website_description, ir.ui.view.arch_db, any res.partner.name with translate=True, etc. |
| odoo_translate_fieldA | Write translations for a simple translate=True field (Char/Text/Selection). Use for: blog.post.name/subtitle/teaser, product.template.name, res.partner.name, account.account.tag.name — any short/plain field. Format: translations = {lang_code: value, ...}. Pass value=null/'' to remove a language's translation (falls back to source_lang). Errors if field.translate is not True (use odoo_translate_html for HTML). Auto-detects Odoo version: v16+ uses update_field_translations() native API, older falls back to ir.translation. |
| odoo_translate_htmlA | Write/read translations for translate=html_translate / translate=xml_translate fields. Use for: blog.post.content, product.template.website_description, hr.job.description, ir.ui.view.arch_db (covers website.page), website.menu.mega_menu_content, event.track.description, forum.forum.guidelines, res.partner.website_description. Three modes: (a) mode='extract' — READ-ONLY. translations arg ignored. Returns the list of translatable terms that Odoo's html_translate engine extracts from source_lang. Each term is an HTML-serialised translatable block (preserves inline tags like ). Use this to see what must be translated before writing. (b) mode='terms' — translations = {lang: {source_term: translated_term, ...}} Direct term map. Terms must match exactly those from mode='extract'. Calls update_field_translations() with JSONB payload. (c) mode='replace' — translations = {lang: full_html_string}. The tool writes each language's HTML through Odoo's native ORM with {'lang': } context. Odoo's html_translate engine aligns terms automatically — no manual term extraction required. This is what Odoo's Website editor does internally. Errors if field.translate is not callable. Requires Odoo 16+. |
| odoo_website_list_snippetsA | List available Odoo website snippet templates (ir.ui.view records with key matching 'website.s_*' or similar). Returns per-snippet: key, name, module, category (structure|content|dynamic|effect|unknown), preview. Use this to discover what snippets can be added to a page. Categories inferred from snippet key patterns and modules. |
| odoo_website_list_page_snippetsA | List snippets currently embedded in a target HTML field. Target can be a blog.post (field=content), website.page (field=arch_db via view_id), product.template (field=website_description), or any HTML field. Parses the HTML with lxml, finds all elements bearing a data-snippet attribute. Returns per-snippet: index, data_snippet, data_name, xpath, text_preview, has_background (detects url() in style), background_url. |
| odoo_website_add_snippetA | Insert a snippet into a target HTML field. Fetches the snippet template from ir.ui.view by key, extracts its root HTML element, applies optional substitutions (text/attr/src changes before insertion), and places it at the specified position relative to an anchor. Positions: 'end' (after last element), 'begin' (before first), 'after' (after anchor_xpath), 'before' (before anchor_xpath), 'replace' (replace anchor_xpath). Substitutions format: {'relative_xpath': value} for text; {'relative_xpath/@attr': value} for attribute; {'relative_xpath/@style:background-image': 'url(...)'} for CSS property; {'relative_xpath/@src': 'https://...'} for image URL. |
| odoo_website_update_snippetA | Update an existing snippet on a target HTML field. Locates the snippet via snippet_xpath (absolute in target), applies substitutions to its descendants via relative xpaths, and writes back. Common use cases: swap background image, change H1/H2 text, update CTA button text+href, change card content. Substitution syntax identical to odoo_website_add_snippet. |
| odoo_website_remove_snippetB | Remove a snippet block from a target HTML field. Locates via snippet_xpath (absolute). Writes back the reduced HTML. |
| odoo_web_loginA | Login to Odoo web interface with user/password. Creates a persistent cookie session for accessing web controllers, exports, reports, and any frontend URL. Session is reused until logout or expiry. |
| odoo_web_callB | Call any Odoo model method via web session (JSON-RPC /web/dataset/call_kw). Works like odoo_execute but uses cookie session instead of XML-RPC. |
| odoo_web_readB | Search and read records via web session (frontend web_search_read format). Supports field specification, domain, limit, offset, order. |
| odoo_web_exportC | Export records to structured data via web session (Odoo export_data). |
| odoo_web_reportC | Download PDF report via web session. Returns base64-encoded PDF. |
| odoo_web_requestC | Raw HTTP request to any Odoo controller URL via web session. Access frontend pages, custom controllers, website routes, etc. |
| odoo_web_logoutC | Destroy web session and logout. |
| public_access_export_xlsxC | Export Odoo list data as XLSX file via web session. Returns base64. |
| public_access_export_csvC | Export Odoo list data as CSV via web session. |
| public_access_report_pdfC | Download PDF report via web session. Route: /report/pdf/{report_name}/{doc_ids}. |
| public_access_report_htmlC | Render report as HTML via web session. |
| public_access_downloadB | Download attachment/binary content by ID via /web/content/{id}. Public route. |
| public_access_imageB | Download image field from record via /web/image/{model}/{id}/{field}. |
| public_access_barcodeC | Generate barcode image via /report/barcode/{type}/{value}. |
| public_access_portal_homeC | Get portal home page content via web session (/my/home). |
| public_access_portal_invoicesC | Get list of portal invoices (/my/invoices). Returns HTML page content. |
| public_access_portal_ordersC | Get list of portal sale orders (/my/orders). Returns HTML page content. |
| public_access_portal_purchasesC | Get list of portal purchase orders (/my/purchase). |
| public_access_portal_ticketsB | Get list of portal helpdesk tickets (/my/tickets). |
| public_access_report_xlsxC | Download XLSX report via OCA reporting-engine (/report/xlsx/{name}/{ids}). |
| public_access_shopC | Get website shop product listing (/shop). Returns HTML. |
| public_access_sitemapC | Download sitemap.xml from Odoo website. |
| odoo_reportC | Generate a PDF report for records. Returns base64-encoded PDF. |
| odoo_versionC | Get Odoo server version info. |
| odoo_refreshA | Send a refresh notification to the user's Odoo browser tab. Call this after creating, updating, or deleting records so the user's list/form/kanban view reloads automatically. Requires l10n_bg_claude_terminal module installed on the Odoo instance. |
| odoo_fp_listA | List fiscal positions with tax action map summary (l10n_bg_tax_admin). Shows position name, auto_apply, country, company, and action mapping count. |
| odoo_fp_detailsB | Get detailed fiscal position with all tax action map entries (l10n_bg_tax_admin). Returns position info plus full action mappings: move types, BG move types, VAT types, document types, narrations, replacement rules, etc. |
| odoo_fp_configureA | Add or update a tax action map entry for a fiscal position (l10n_bg_tax_admin). Provide action_id to update existing entry, or position_id to create new. Use odoo_fp_types for available selection values. |
| odoo_fp_remove_actionC | Remove a tax action map entry from a fiscal position (l10n_bg_tax_admin). |
| odoo_fp_typesA | Get available selection values for fiscal position configuration (l10n_bg_tax_admin). Returns move_types, bg_move_types, doc_types, and type_vat. Use as reference when calling odoo_fp_configure. Set live=true to fetch current values from Odoo instead of cached. |
| odoo_stock_product_flip_to_storableA | Flip a product from consumable (is_storable=false) to storable (is_storable=true) when the product ALREADY has stock.move records. Bypasses Odoo's ORM constraint 'You can not change the inventory tracking of a product that was already used' via raw SQL in an ir.actions.server. Then inserts a stock.quant DIRECTLY (not through an inventory adjustment wizard) so no duplicate SVL is created — existing SVLs stay intact. Use when a GRN/bill was recorded for a product that was mistakenly set as consu. ALWAYS use dry_run=true first to preview impact. Returns full pre/post snapshot. |
| odoo_translate_context_awareA | Translate Odoo records using Claude with rich domain context for natural, fluent results (not literal). AUTO-DETECTS field kind and handles both: (1) simple char/text fields (e.g. ir.ui.menu.name, account.account.name) → batch translate via update_field_translations; (2) HTML/XML fields (e.g. ir.ui.view.arch_db, website.page, product.template.website_description) → extracts canonical terms via get_field_translations, translates each term preserving inline HTML tags (, , ...), writes back in terms mode. Context to LLM: Odoo model, parent chain for menus, existing translations, user-supplied domain hint, field kind (simple/html/xml). Requires Odoo 16+. Requires ANTHROPIC_API_KEY env var (per-tenant override: ANTHROPIC_API_KEY_). Recommended models: 'claude-haiku-4-5' (menu labels, fast), 'claude-sonnet-4-6' (balanced, website pages), 'claude-opus-4-7' (complex legal/accounting terminology). ALWAYS use dry_run=true first to review proposals. |
| odoo_stock_mo_delete_draftA | Safely DELETE a draft or cancelled mrp.production with cascade (raw stock.moves, finished stock.moves, procurement.group if orphaned). Bypasses Odoo's ORM 'cannot be deleted' constraint by forcing state='cancel' via raw SQL, then using DELETE statements inside an ir.actions.server. Refuses if MO has any SVL, stock.move with quantity > 0, or an already-done state. ALWAYS use dry_run=true first. |
| odoo_record_backupA | Read full field snapshot of one or more records (any model) and return as a JSON structure. Use BEFORE destructive operations to capture state for possible rollback. Returns a dict with metadata (date, connection alias, model, ids, field count) plus the records themselves. Does NOT write to disk — caller decides what to do with the JSON. |
| odoo_stock_close_unaccounted_valueA | Create an Inventory Valuation journal entry (Dr stock valuation / Cr GRNI/stock-input) for a stocked movement that was valued but not accounted (account_move_id=false), then bind the new account.move back to the record. Version-aware: works on stock.valuation.layer (Odoo 14-18) OR stock.move (Odoo 19+). GRNI account auto-detection order: (a) v14-18 → category.property_stock_account_input_categ_id; (b) v19 with l10n_bg_stock_account → category.l10n_bg_stock_input_account_id; (c) v19 vanilla → category.account_stock_variation_id (fallback). User can override via grni_account_id parameter. Refuses if record is already accounted or category is not real_time. ALWAYS use dry_run=true first. |
| odoo_stock_initial_importA | Import opening stock balances (initial inventory) via direct SQL INSERT, bypassing ORM overrides (e.g. custom modules that null out stock.move.name). Version-aware: v14-v18 creates stock.move + stock.move.line + stock.valuation.layer + stock.quant; v19 creates stock.move (with value/price_unit/remaining_qty/remaining_value/is_valued=true/is_in=true fields — SVL does not exist) + stock.move.line + stock.quant. All datetimes anchored at 23:59:59 in the caller's timezone, converted to UTC before INSERT. Writes a JSON snapshot to /backups// before execution. ALWAYS use dry_run=true first to preview the plan and catch category/location/product errors. For real_time valuation, follow up with odoo_stock_initial_opening_journal to book the account entry (SQL INSERT does NOT create account.move). |
| odoo_stock_initial_deleteA | Delete wrong opening stock balances — cascade-removes stock.move (is_inventory=TRUE) records, their stock.move.line, and (v14-v18) stock.valuation.layer; then zeros out stock.quant on affected (product, location, lot). Bypasses Odoo's ORM guard 'You can not delete product moves if the picking is done' via raw SQL in an ir.actions.server + env.cr.commit(). Version-aware: v14-v18 DELETEs SVL→SML→SM; v19 DELETEs SML→SM (SVL doesn't exist). PRE-FLIGHT: refuses if any affected SVL/stock.move has account_move_id set (orphan journal entries would remain). Caller must reverse those first. ALWAYS writes a full JSON backup to /backups// BEFORE any delete. ALWAYS use dry_run=true first to see the impact scope. |
| odoo_stock_initial_opening_journalA | Book the opening-balance journal entry for a previous SQL-inserted initial stock (complements odoo_stock_initial_import — SVL/stock.move written via raw SQL do NOT auto-create account.move even for real_time valuation). Creates ONE account.move (MISC journal, state=posted) with: DR lines grouped by category.property_stock_valuation_account_id (e.g. 302 Materials, 303 Products); CR contra account (default: code '122000' Retained earnings from prior years). Version-aware: v14-v18 reads stock.valuation.layer for the date; v19 reads stock.move (is_inventory=true, is_valued=true) for the same date — totals the 'value' column. DUPLICATE GUARD: before create, scans account.move.line for the same accounts on the same date — if any posted lines found, refuses and returns them (Alpinter lesson: comprehensive opening entries often already include the stock lines). ALWAYS use dry_run=true first. |
| google_authA | Authenticate with Google OAuth2 for Gmail and Calendar access. Requires credentials.json from Google Cloud Console (Desktop app type). First call opens browser for consent. Token is saved for reuse. |
| google_auth_statusB | Check Google authentication status. |
| google_gmail_searchA | Search Gmail messages. Uses Gmail search syntax (e.g. 'from:user@example.com', 'subject:invoice', 'after:2026/01/01', 'is:unread'). |
| google_gmail_readA | Read a specific Gmail message by ID. Returns full body, headers, and labels. |
| google_gmail_sendB | Send an email or reply to an existing message. |
| google_gmail_labelsA | List all Gmail labels (folders). |
| google_calendar_listA | List all available Google calendars. |
| google_calendar_eventsB | List upcoming calendar events. Supports time range and text search. |
| google_calendar_create_eventC | Create a new calendar event. |
| google_calendar_update_eventB | Update an existing calendar event. Only provided fields are changed. |
| google_calendar_delete_eventC | Delete a calendar event. |
| telegram_configureA | Set Telegram API credentials (api_id and api_hash from my.telegram.org). |
| telegram_authA | Authenticate with Telegram. Two-step process: 1) Call with phone → code is sent to Telegram. 2) Call with phone + code → authenticated. If 2FA enabled, provide password too. |
| telegram_auth_statusA | Check Telegram authentication status. |
| telegram_get_dialogsC | List recent Telegram chats (users, groups, channels). |
| telegram_search_contactsC | Search Telegram contacts by name or username. |
| telegram_get_messagesA | Read messages from a Telegram chat. Chat can be @username, phone, or numeric ID. |
| telegram_send_messageB | Send a Telegram message. Chat can be @username, phone, or numeric ID. |
| open_connection_managerA | Open the Connection Manager GUI (desktop app). Launches GTK4 version on Linux, Qt6 on Windows/macOS. Use this when the user wants to visually manage connections, configure Portainer/GitHub, manage SSH keys, or see active sessions. |
| ssh_executeA | Execute a command on a remote server via SSH. Uses SSH config from connections.json (connection's ssh section). Provide either a connection alias (to use saved SSH config) or explicit host/user. |
| git_remoteB | Run git commands on a remote server via SSH. Shortcut for common git operations (pull, status, log, branch, diff) on remote repositories. Provide the connection alias and repo path. |
| github_apiA | Call GitHub REST API directly. Uses the GitHub token from local_profile.json. For operations not covered by the GitHub MCP server, or when it's not running. |
| identifyA | Identify yourself to load your personal settings and connections. Call this at the start of a session. Returns your saved connections. |
| who_am_iA | Show current user identity and active connection. |
| user_connection_addB | Add/update a personal Odoo connection (saved per-user). Supports Odoo, SSH, and Portainer settings. |
| user_connection_listB | List your personal connections. |
| user_connection_activateA | Activate one of your personal connections as the working connection. |
| user_connection_deleteA | Delete a personal connection. |
| memory_listA | List memory files. Shows personal files (for current user) and shared files. Use scope='personal', 'shared', or 'all' (default). |
| memory_readA | Read a memory file by filename. Searches personal first, then shared. |
| memory_writeA | Write/update a memory file. Saves to personal storage by default. Content should be markdown with YAML frontmatter (name, description, type). |
| memory_deleteC | Delete a memory file from personal or shared storage. |
| memory_shareA | Share personal memory file(s) — copies to shared storage so colleagues can pull. Use filename='*' to share ALL personal files. |
| memory_pullA | Pull shared memory file(s) into your personal storage. Use filename='*' to pull ALL shared files at once. If a file already exists locally, it gets overwritten with the shared version. |
Prompts
Interactive templates invoked by user choice
| Name | Description |
|---|---|
No prompts | |
Resources
Contextual data attached and managed by the client
| Name | Description |
|---|---|
No resources | |
Latest Blog Posts
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/rosenvladimirov/odoo-claude-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server