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 |
Instructions
Guidance the server publishes about itself, which clients place ahead of the tool catalog so the model reads it before choosing anything.
This server publishes no instructions, or was last inspected before Glama recorded them.
Capabilities
Features and capabilities supported by this server
Protocol revision2025-11-25
| 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
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
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