Skip to main content
Uniconta is a read and guardrailed-write connector, called via tools/call over POST /uniconta/mcp. It has 21 read tools and 4 write tools, and the write tools work only on unposted lines in the daily journal (kassekladde). The connector is connected with a form in the portal, with no OAuth: a dedicated Uniconta Server-Login User (username + password) plus a Company ID. See Forbind Uniconta.
Endpoint: https://mcp.consile.ai/uniconta/mcp. Uniconta is its own named connector with only its own tools. Each tool is exposed as uniconta__<tool> (e.g. uniconta__get_account_balance); your AI assistant invokes these for you, so the names below are the bare tool names.Each additional Uniconta company the customer adds as a portal gets its own endpoint, https://mcp.consile.ai/uniconta-2/mcp, uniconta-3, and so on, with tools prefixed uniconta-2__ etc. Every tool is listed with a title and annotations. Read tools carry annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: false }; the write tools are described under Write safety.Besides the connector tools, tools/list on this endpoint also returns one unprefixed system tool, connect_account (no arguments). It returns a link, valid for 10 minutes, that the user opens in the browser to enter the Uniconta login in the portal. It does not read any Uniconta data.
The read tools, including query and aggregate, cannot write. Only the four daily-journal write tools write, and only after confirm: true. They create, update and delete unposted journal lines and post explicit lines to the ledger. No tool changes master data (debtors, creditors, items), invoices or orders, or posted ledger rows.

Shared parameters

Most list tools accept a row cap; several support search, exact-account and date-range filtering; and the high-volume reads (list_inventory_items, query) add sorting, paging and field selection.
integer
default:"50"
Max rows to return, an integer from 1 to 1000 (default 50). Values outside that range are rejected, not clamped: the call fails with isError: true and Tool invocation failed., as does any other argument that breaks the tool’s input schema.
Name search. Wildcards are added automatically (acme becomes *acme*); pass your own * to control matching. Available on the debtor, creditor, G/L-account and inventory list tools.
string
Exact account number to filter on (debtor, creditor or G/L account, depending on the tool).
string (YYYY-MM-DD)
Inclusive date range, e.g. "2025-01-01" / "2025-12-31". Available on the invoice, transaction and posting list tools.
integer
Rows to skip before the page is returned. Use with limit and follow the result’s nextOffset to page. Available on list_inventory_items, list_inventory_transactions, list_journal_lines and query.
string[]
Return only these properties per row (trims the payload on wide entities), up to 40 names. Available on list_inventory_items and query. Custom fields only exist on the …ClientUser entity variants.

Result shape

A plain list result is { entity, count, total, items: [...] }, where total is the full row count before the limit cap and count is the number of rows returned. When a call sorts (sortBy, orderBy) or pages (offset), the full count is unknown: total is omitted and the result carries truncated: true on a full page. offset and nextOffset are added only when the request itself passed an offset; a sort-only read (no offset) returns truncated: true on a full page without any cursor. A fields projection that names a property present in no returned row echoes it in unknownFields. A broad, unfiltered read of a large posting table can be slow or fail with the generic Tool invocation failed.. Narrow such reads with account, a date range or search, or use aggregate for totals.

Companies

list_companies

List the Uniconta companies the connected Server-Login User can access (CompanyId, name, CVR/registration number, country). Arguments: none. Returns { count, companies: [...] }. This lists every company the Server-Login User can access. All other tools read only the Company ID the connection was set up with; there is no company argument. This tool does not depend on the configured Company ID, so it also succeeds when that ID is wrong, which makes it a quick way to tell a bad login from a bad Company ID.

Debtors (customers)

list_debtors

List debtors (customers) with account, name, address, currency, balance (CurBalance), overdue and credit limit.
Name search (wildcards added automatically).
string
Exact debtor account number.
string
CVR / registration number (CompanyRegNo).
integer
default:"50"

list_debtor_open_items

Open (unpaid) debtor items (accounts-receivable / aging view): account, voucher, invoice, due date and AmountOpen (outstanding).
string
Exact debtor account number.
integer
default:"50"

list_debtor_invoices

Issued customer invoices (debitorfakturaer): InvoiceNumber, account, dates, net/VAT/total amounts and Paid flag.
string
Exact debtor account number.
string (YYYY-MM-DD)
From date; pairs with toDate as a range.
string (YYYY-MM-DD)
integer
default:"50"

list_debtor_orders

Sales orders (salgsordrer): OrderNumber, account, name, amounts and status.
string
Exact debtor account number.
integer
default:"50"

list_debtor_transactions

A debtor’s posted ledger movements (debitorposteringer): date, voucher, invoice, amount and text. For the unpaid/overdue view with due dates and outstanding amounts use list_debtor_open_items instead. Pass account to limit the result to that debtor; without it the tool returns all G/L postings, like list_gl_transactions. If a debtor and a creditor share an account number, rows for both are returned; the rows’ DCType tells them apart.
string
Exact debtor account number.
string (YYYY-MM-DD)
string (YYYY-MM-DD)
integer
default:"50"

Creditors (suppliers)

list_creditors

Creditors (suppliers) for accounts-payable / spend questions: account, name, currency, balance, overdue and payment method.
Name search (wildcards added automatically).
string
Exact creditor account number.
integer
default:"50"

list_creditor_open_items

Open (unpaid) creditor items (accounts-payable view): account, voucher, due date and outstanding amount.
string
Exact creditor account number.
integer
default:"50"

list_creditor_transactions

A creditor’s posted ledger movements (kreditorposteringer): date, voucher, invoice, amount and text. For the unpaid/overdue view use list_creditor_open_items instead. Pass account to limit the result to that creditor; without it the tool returns all G/L postings, like list_gl_transactions. If a debtor and a creditor share an account number, rows for both are returned; the rows’ DCType tells them apart.
string
Exact creditor account number.
string (YYYY-MM-DD)
string (YYYY-MM-DD)
integer
default:"50"

Finance / general ledger

list_gl_accounts

The chart of accounts (kontoplan): Account, Name, AccountType, Balance and this-year / last-year figures.
Account name search (wildcards added automatically).
string
Exact G/L account number.
integer
default:"50"

get_account_balance

Read one G/L account’s balance and this-year figures by account number: the direct “balance of account X” answer. Returns the single matching account row, or null if no account matches.
string
required
G/L account number, e.g. "1010".

list_gl_transactions

General-ledger postings (finansposteringer): date, account, voucher, text, amount, VAT and transaction type.
string
Exact G/L account number.
string (YYYY-MM-DD)
string (YYYY-MM-DD)
integer
default:"50"

list_vat_codes

VAT / moms codes with rates (Vat, Name, Rate, Account, VatType), needed to interpret VAT on invoices and postings.
integer
default:"50"

Inventory (products)

list_inventory_items

Products / inventory items (varer): Item, Name, prices (sales/cost/purchase), unit, group, EAN and quantity on stock. Optionally sort (returns only the top limit rows), page with offset, trim wide rows with fields, and set includeCustomFields so the company’s own custom/user-defined fields come along. Uniconta stores no creation date on items, so “newest created product” is not answerable here; sortBy: "last_movement" gives the most recently transacted items instead.
Product name search (wildcards added automatically).
string
Exact item number.
string
Exact product group code.
boolean
default:"false"
Read the InvItemClientUser entity variant so the company’s custom/user-defined item fields are included in each row (they are absent on the base entity).
enum
One of item, name, sales_price, cost_price, quantity, last_movement. Sorts and returns only the top limit rows. Uniconta has no item creation date, so last_movement is the date of the last stock movement.
boolean
default:"true"
true = highest/newest first (default); false = ascending.
integer
default:"50"
integer
Paging (follow nextOffset).
string[]
Return only these properties per row.

list_product_groups

Inventory product groups (Group, Name) used to categorise items.
integer
default:"50"

list_inventory_transactions

Inventory postings / stock movements (lagerposteringer): Item, ItemName, Date, Qty (negative on a sale), DCAccount (the debtor/creditor on the line), AccountName, InvoiceNumber, NetAmount and MovementType. This is how you read the actual sales lines for an item (qty < 0) with their invoice date and customer. To count units sold in a product group, first get the item numbers via list_inventory_items (group=…), then call this filtered to those items plus the date range and sum the negative Qty.
string
Item number (exact). Multiple via Uniconta list syntax, e.g. "1001;1002;1003".
string
Debtor/creditor account on the line (DCAccount).
string (YYYY-MM-DD)
string (YYYY-MM-DD)
integer
default:"50"
integer
Paging (follow nextOffset).

Daily journals (kassekladde)

list_journals

The company’s daily journals: the key (Journal), name, number series, default account and offset account with their types, default VAT, the Blocked flag, the number of unposted lines, the voucher settings (GenerateVoucher, OneVoucherForAll, NewVoucherPerLine), DateFunction and dimensions. Use it to find the journal key the line tools need. A blocked journal cannot be changed or posted through Consile.
string
Exact journal key, to fetch one journal.
integer
default:"50"

list_journal_lines

The unposted lines of one daily journal: RowId (the lineId the write tools take), date, account type, account and account name, offset account, VAT codes, text, signed Amount (positive = debit), Debit/Credit, voucher, invoice, due date, project and dimensions. Only lines of the named journal are returned. Posted lines are no longer in the journal; read them with list_gl_transactions. This is the review step before post_journal_lines. The result is the list shape plus journal.
string
required
Journal key from list_journals.
string
Exact account on the account side.
string (YYYY-MM-DD)
string (YYYY-MM-DD)
integer
default:"50"
integer
Paging (follow nextOffset).

Advanced

query

The read-only escape hatch: fetch rows for any Uniconta Query entity with raw filters. Use it for entities not covered by a dedicated tool (e.g. "ProjectClient"). It can only read, never write. Optionally sort via orderBy (returns only the top limit rows), page with offset, and trim wide rows with fields. Custom/user-defined fields are only returned, and only filterable, on the …ClientUser entity variants (e.g. InvItemClientUser); on the base entity a filter on a custom field is silently ignored. For per-group totals across a whole table, prefer aggregate.
string
required
Uniconta entity / table name, e.g. "DebtorClient", "GLTransClient". Use the …ClientUser variant (e.g. "InvItemClientUser") to include custom fields.
array
default:"[]"
Uniconta query filters; empty means all rows. Each filter is { "PropertyName": string, "FilterValue": string }. FilterValue can be exact, a wildcard (*abc*), a range (a..b) or a list (a;b;c).
string
Property to sort by, e.g. "Item" or "Date".
boolean
default:"true"
When orderBy is set: true = descending (default), false = ascending.
integer
default:"50"
integer
Paging (follow nextOffset).
string[]
Return only these properties per row.

aggregate

Group and sum any Uniconta Query entity and return only the per-group totals, e.g. contribution margin per product group across the whole item catalogue in one call. It reads up to about 50,000 matching rows per call, so use it for totals beyond the per-call row limit of the other tools. It rejects groupings over 1000 groups (the call fails with the generic Tool invocation failed.), and if the result says truncated: true you should narrow the filters or date range rather than retry.
string
required
Uniconta Query entity, e.g. "InvTransClient" or "InvItemClientUser" (the …ClientUser variant is required for custom/user-defined fields).
array
default:"[]"
Filters applied before aggregating; empty means all rows.
string[]
default:"[]"
Properties to group by (max 3), e.g. ["Group"]. Empty means one grand-total row.
string[]
default:"[]"
Numeric properties to sum per group (max 10). Unparseable values are skipped and counted in the result’s nonNumeric tally (never summed as 0).
string
default:"Date"
Property the fromDate/toDate range filters on.
string (YYYY-MM-DD)
string (YYYY-MM-DD)
string
Stable sort key, recommended on large tables for consistent totals.
Returns { entity, groupCount, rowsScanned, pages, truncated, groups: [{ key, count, sums }] }. nonNumeric is included only when it is non-empty, and there is no groupBy key in the result.

Recently added items (not yet available)

list_recently_added_items

Meant to list the inventory items that appeared most recently. Uniconta stores no item creation date, so list_inventory_items cannot answer this. Not available yet: the tool returns a message saying so, as a normal result (not isError), and no item data. For the most recently transacted items use list_inventory_items with sortBy: "last_movement".
string (ISO)
Only items from this date on, e.g. "2026-01-01".
integer
default:"50"

Write safety: guardrail model

The four write tools share one confirmation model. Read tools are annotated readOnlyHint: true, destructiveHint: false, openWorldHint: false. Write tools carry readOnlyHint: false, destructiveHint: true and openWorldHint: false; idempotentHint is true on update_journal_lines and delete_journal_line and false on create_journal_lines and post_journal_lines.
  1. Every write is preview-first. A call without confirm: true never changes anything. The tools check the journal and the lines you name first, so a dry-run can already fail with a clear message when the journal or a line does not exist. Otherwise you get a preview of the exact request and nothing is written.
  2. confirm: true is required to apply, with no exceptions. post_journal_lines always takes two calls, because the confirming call must send back the expectedState from a preview. See The confirm argument.
  3. Writes stay in the daily journal. The tools create, update and delete unposted lines and post explicit lines. Nothing else can be changed: no master data (debtors, creditors, items), no invoices or orders and no posted ledger rows.
  4. Lines are addressed by lineId within one journal. A lineId is the line’s RowId from list_journal_lines. Every line must be an unposted line in the journal you name, or the call changes nothing. A journal that is blocked in Uniconta is refused.
  5. Posting has its own gate. post_journal_lines posts only the explicit lineIds you pass (max 50 per call, never the whole journal), and the confirming call must echo the preview’s expectedState. If a line’s date, account or offset account (or their types), amount, VAT codes, text, voucher, invoice or due date changed in between, nothing is posted. Posting is irreversible.
  6. Updates change only the fields you pass. update_journal_lines keeps every field of the line that you do not pass. The confirming call applies your changes to the line as it is at that moment.
  7. Uniconta’s own rights still apply. Read access is enough for every read tool. To create, change and post lines, the Server-Login User needs write access to the daily journal and the right to post in Uniconta. Without them Uniconta refuses the change and nothing happens (see Errors).
These are safety defaults built into the Uniconta tools. See Handlinger & guardrails for the policy across connectors.

Preview shape

When a write is not confirmed (confirm omitted or false), the tool returns this as a normal (non-error) tool result instead of writing to Uniconta:
string
POST, PUT or DELETE. Every Uniconta preview has a body, including the DELETE of delete_journal_line (the line to delete).
string
The Uniconta endpoint the confirming call would send the request to.
object
Only on post_journal_lines: { expectedState }, which the confirming call sends back as expectedState. Treat the value as an opaque string. This preview also carries its own confirmHint.

Write tools (4 guardrailed)

Write tools change data in Uniconta. Every one is preview-first: without confirm: true you get a preview and nothing is changed. Creating, updating and deleting lines never posts anything. Only post_journal_lines posts, and only the lines you confirm.

create_journal_lines

Create unposted lines in a daily journal. Nothing is posted.
string
required
Journal key from list_journals.
object[]
required
1-50 lines. Each line:
  • required: date (YYYY-MM-DD), account, amount (signed, in the company currency: positive = debit, negative = credit on the account side)
  • optional: accountType (ledger, debtor or creditor; default ledger), offsetAccount, offsetAccountType (same values; defaults to ledger when offsetAccount is given), text (max 250 characters), vat, offsetVat, voucher (integer; omit to let the journal’s number series assign one), invoice, dueDate (YYYY-MM-DD), documentDate (YYYY-MM-DD), project, dimension1 to dimension5
boolean
Set true to apply; omit for a dry-run preview.
A line with an offset account balances itself. Lines without one must net to zero per voucher before Uniconta will post them; the preview says how many lines have no offset account. The preview summarises the debit, credit and net totals. The lines are linked to the journal when they are created. Not idempotent: a second confirmed call creates the lines again. Returns { created, journal, hint }; read the new lines and their RowIds with list_journal_lines. Requires confirmation: always.

update_journal_lines

Update unposted lines by lineId. Only the fields you pass are changed. Posted lines cannot be changed; post a correcting line instead.
string
required
Journal key from list_journals.
object[]
required
1-50 patches: lineId plus the fields to change (same fields as create_journal_lines, all optional). A lineId may appear only once.
boolean
Set true to apply; omit for a dry-run preview.
The preview names the lines and the changed fields and carries the merged rows. Returns { updated: [lineId, ...], journal }. See rule 6 above. Requires confirmation: always.

delete_journal_line

Delete one unposted line. The line is fetched first and described in the preview (line id, date, accounts, amount, text). A wrong or already posted lineId fails in the preview call. Posted ledger rows cannot be deleted.
string
required
Journal key from list_journals.
integer
required
The unposted line to delete (RowId from list_journal_lines).
boolean
Set true to apply; omit for a dry-run preview.
Returns { deleted, journal }. Requires confirmation: always.

post_journal_lines

Post specific unposted lines to the ledger (bogfør). This is irreversible: posted rows cannot be edited or deleted, only corrected with new lines.
string
required
The journal the lines belong to.
integer[]
required
1-50 exact unposted line ids (duplicates are ignored).
string (YYYY-MM-DD)
Posting date passed to Uniconta (default today). Lines keep their own date unless the journal’s DateFunction says otherwise.
string
Comment stored on the posting, max 250 characters (default Posted via Consile MCP).
string
Copy preview.state.expectedState from the preview. Required together with confirm: true.
boolean
Set true to post; omit for a dry-run preview.
Flow:
  1. Call without confirm. Every id must be an unposted line in that journal; otherwise the call fails naming the ids (Not unposted lines in journal "<key>": … Nothing was changed.). The preview lists each line (id, date, accounts, amount, text) with debit, credit and net totals, says how many other unposted lines in the journal are not included, and returns preview.state.expectedState.
  2. Re-run with confirm: true and expectedState. Without expectedState the call is refused. If one of the values listed in rule 5 of the guardrail model changed since the preview, it fails with Lines changed since the preview: <ids>. Re-run without confirm to review the current state. This call posted nothing.
After posting, the connector reads the journal again and reports what actually happened:
integer[]
The requested line ids that are no longer unposted.
integer[]
Requested line ids that are still in the journal.
integer
Unposted lines left in the journal, including lines you did not select.
string
Present only when stillUnposted is not empty: Uniconta accepted the request, but those lines are still unposted. Check the journal in Uniconta before retrying.
The result also carries journal, postingDate and result (Uniconta’s response). If a posting call times out or fails without a clear answer, check list_journal_lines and list_gl_transactions before retrying, because the lines may already be posted. Requires confirmation: always, plus expectedState.

Access levels (per user)

An account administrator chooses one of two access levels for Uniconta per user, on the portal’s Team page, or picks the exact tools under Tilpasset (custom). All levels cost the same. e-conomic has the same levels. A level only gives tools the organization has switched on. For an organization that bought Uniconta before 2026-10-07, the six daily journal tools (list_journals, list_journal_lines and the 4 write tools) are off until an administrator activates them on the connector’s page in the portal; until then tools/list holds the other 19 read tools. See Tools and new tools. Under Read only:
  • tools/list on every Uniconta endpoint omits the 4 write tools (connect_account is still listed).
  • A direct tools/call to a write tool returns a tool result with isError: true explaining that the tool is not enabled for the user. Nothing is sent to Uniconta.
  • The initialize result carries instructions telling the model the session can only read.
The level applies to all of the user’s Uniconta portals. A user for whom no level has been chosen has Full access. The level is enforced by Consile per user; colleagues on Full access keep their write tools, and the Server-Login User’s own rights in Uniconta still apply (rule 7 above). Clients that cache tools/list should start a new session after a level change; a cached write tool is refused when called. A user who holds no seat on Uniconta still sees the tool list, but every tools/call is refused with a seat message (see Errors).

Errors and timeouts

Tool failures come back as a normal tool result with isError: true and one text block. A rejected login and the write tools’ failures carry an explanatory message (Uniconta’s own refusal or the connector’s own checks), so the AI can correct the call; other read failures return the generic text: After connecting, make one read call (e.g. get_account_balance) to confirm that the login and Company ID work; list_companies tells a bad login from a bad Company ID. A write that fails with a timeout may still have been applied in Uniconta, so check there before repeating it. See Errors & limits for the protocol-level errors and rate limits shared by all connectors.

Code examples