odoo-bookkeeping-mcp
Server Configuration
Describes the environment variables required to run the server.
| Name | Required | Description | Default |
|---|---|---|---|
| ODOO_DB | Yes | The name of the Odoo database. | |
| ODOO_URL | Yes | The URL of the Odoo instance. | |
| ODOO_API_KEY | Yes | The API key for the Odoo user. | |
| ODOO_USERNAME | Yes | The Odoo username (typically an email address). | |
| ODOO_MCP_ALLOW_POST | No | Gates posting invoices/journal entries and registering payments. | true |
| ODOO_MCP_ALLOW_UNLINK | No | Gates the odoo_unlink tool (permanent record deletion). | false |
| ODOO_MCP_ALLOW_RECONCILE | No | Gates the reconcile_lines tool. | true |
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
} |
| prompts | {
"listChanged": false
} |
| resources | {
"subscribe": false,
"listChanged": false
} |
| experimental | {} |
Tools
Functions exposed to the LLM to take actions
| Name | Description |
|---|---|
| odoo_search_readA | Search and read records of ANY Odoo model in one call. model: technical model name, e.g. "account.move", "res.partner", "project.budget.line". domain: Odoo domain, e.g. [["state", "=", "draft"]]. Empty/omitted matches all records (subject to record rules). fields: field names to return; omit for all fields. limit: max records to return (default 80, use 0 for no limit -- careful on large models). order: e.g. "date desc, id desc". |
| odoo_fields_getA | List every field on an Odoo model: type, label, required, readonly, relation target, selection options. Use this before create/write on an unfamiliar model instead of guessing field names. |
| odoo_createA | Create ONE record on any model. Returns the new record's id. Example: odoo_create("res.partner", {"name": "Acme LLC"}). For accounting documents prefer the dedicated accounting.* tools (they set up lines/taxes/journals correctly) -- use this for anything they don't cover. |
| odoo_writeC | Update one or more existing records with the given field values. |
| odoo_unlinkA | Permanently delete one or more records. THIS CANNOT BE UNDONE. Disabled by default (ODOO_MCP_ALLOW_UNLINK=false) because Odoo has no "undo" for a deleted record -- unlike posted accounting entries, which can always be reversed with a credit note / reversal entry. Set ODOO_MCP_ALLOW_UNLINK=true in the server's environment to allow this tool to actually delete anything. |
| odoo_call_methodA | Call ANY method on an Odoo model -- the universal escape hatch. Use this for workflow actions the dedicated tools don't wrap yet, e.g. odoo_call_method("account.move", "button_draft", [123]) or odoo_call_method("project.budget", "action_approve", [7]). ids may be empty for @api.model methods that don't act on records. |
| create_invoiceA | Create a DRAFT customer invoice or vendor bill. move_type: "out_invoice" (customer invoice), "out_refund" (credit note), "in_invoice" (vendor bill), "in_refund" (vendor credit note). lines: list of dicts, each with at least "name" (description), "quantity", "price_unit". Optional per line: "product_id", "account_id", "tax_ids" (list of tax ids), "analytic_distribution" (e.g. {"": 100.0}). Always created in draft -- call post_invoice() to post it once you're satisfied. |
| update_invoiceA | Update a draft invoice/bill's header fields and/or replace its lines entirely. Odoo will reject this once the move is posted -- use a reversal/credit note for posted documents instead. lines, if given, REPLACES all existing lines (same line-dict shape
as create_invoice's |
| post_invoiceA | Post (confirm) a draft invoice/vendor bill. Irreversible in the sense that a posted move must be reversed/credited, not edited, to correct it afterwards. |
| search_invoicesC | Search customer invoices / vendor bills / credit notes. Example domain: [["move_type", "=", "in_invoice"], ["state", "=", "draft"]]. |
| get_invoiceA | Full detail of one invoice/bill including its lines. |
| create_journal_entryA | Create a DRAFT manual journal entry (move_type='entry'). lines: list of dicts, each with "account_id" and either "debit" or "credit" (or both, defaulting to 0) plus optional "name" (label), "partner_id", "analytic_distribution". Must balance (total debit == total credit) -- Odoo enforces this on post. |
| update_journal_entryA | Update a draft journal entry's header and/or replace its lines
entirely (same line-dict shape as create_journal_entry's |
| post_journal_entryA | Post a draft journal entry. Same irreversibility caveat as post_invoice -- correct a posted entry with a reversal, not a write. |
| reverse_journal_entryA | Create and post a reversal of an already-posted move -- the correct way to undo a posted entry (never edit or delete a posted move directly). |
| search_journal_entriesB | Search journal entries/invoices/bills of any move_type. Example domain: [["move_type", "=", "entry"], ["date", ">=", "2026-01-01"]]. |
| register_paymentA | Register a payment against a posted invoice/bill via Odoo's standard account.payment.register wizard model (keeps reconciliation correct -- never write account.payment directly). |
| reconcile_linesA | Reconcile a set of account.move.line ids against each other (e.g. a payment line against an invoice line). All lines must share the same partner and a reconcilable account. |
| search_unreconciled_linesA | Find open (unreconciled) receivable/payable move lines, e.g. to match a payment to its invoice. |
| profit_and_lossA | Profit & Loss (income statement) for a date range: income and expense accounts, from posted journal items only. |
| balance_sheetA | Balance Sheet (assets / liabilities / equity) as of a date, from posted journal items only, computed as cumulative balances from the earliest entry up to as_of_date. |
| trial_balanceB | Trial balance: opening + period debit/credit + closing balance per account, for a period. |
| general_ledgerA | All posted journal items on one account for a period, in date order, with a running balance. |
| aged_receivableB | Aged receivable: open customer invoice balances, bucketed by days overdue as of a date. |
| aged_payableA | Aged payable: open vendor bill balances, bucketed by days overdue as of a date. |
| list_budgetsA | List project budgets, optionally filtered by project and/or state (e.g. "draft", "submitted", "approved", "active"). |
| get_budgetA | Full detail of one budget, including every BOQ line with its planned/actual/ETC/EAC figures -- read directly from Odoo, never recomputed here. |
| create_budget_lineA | Add a new BOQ line to a budget. Either give planned_qty + planned_unit_cost, or set is_lump_sum=True with planned_total_cost. |
| update_budget_lineA | Update any field(s) on a BOQ line: planned_qty, planned_unit_cost, planned_total_cost, etc_mode ("auto"/"manual"), manual_etc, name, section_id, cost_category_id, task_id, work_package_id, etc. Never write "auto_etc", "effective_etc" or "forecast_cost_at_completion" directly -- they are always computed by Odoo from planned/actual/manual_etc; Odoo will simply ignore or reject an attempt to write them. To move the forecast, set etc_mode="manual" and manual_etc= instead. |
| submit_budgetB | Move a draft budget to Submitted (action_submit). |
| approve_budgetC | Approve a submitted budget (action_approve). |
| activate_budgetA | Activate an approved budget so it can receive real transactions (action_activate). |
| budget_vs_actualA | Budget-vs-actual summary for one budget: per line and totals for planned cost, actual cost, effective ETC, forecast EAC and available budget -- all read straight from Odoo's own computed fields, never recalculated here. |
| search_budget_linesA | Search BOQ lines across any budget/project. Example domain: [["category_type", "=", "labor"], ["budget_state", "=", "active"]]. |
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/Andrewraof/Bookkeeping-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server