Skip to main content
All Business Central tools are read-only and are called via tools/call over POST /business-central/mcp. The connector reads Microsoft Dynamics 365 Business Central online and is connected through OAuth with a Microsoft work or school account (see Forbind Business Central). You need an active Business Central subscription, and your user must hold a seat on it (assigned under Team in the portal, see Team).
The connector is in early access. It currently serves five tools: three discovery tools (list_environments, list_companies, get_company_information) and a generic, allow-listed query tool (query_entity) with its companion (list_entity_metadata). The Business Central description in the portal’s Marketplace also lists tools that are not available yet. This page documents only what is served today.
Endpoint: https://mcp.consile.ai/business-central/mcp. Business Central is its own named connector with only its own tools. Tool names are namespaced business-central__<tool> (e.g. business-central__list_companies); the bare names are used below for readability. A bare name in a request returns Unknown tool.The connector is multi-instance: one instance covers one Microsoft Entra tenant, including all of its environments and companies. An additional tenant is added as a portal by an administrator and served at its own endpoint, e.g. https://mcp.consile.ai/business-central-2/mcp, with tools named business-central-2__<tool>.
For an account with an active Business Central subscription, tools/list returns the five business-central__* tools plus the unprefixed system tool connect_account. Without a subscription only connect_account is listed, and the initialize result includes instructions explaining how to get access. A user without a seat still sees the tools, but every call is refused. Every tool has a title and the annotations readOnlyHint: true, destructiveHint: false and openWorldHint: false. A successful result contains the payload twice: as JSON text in content and as the same object in structuredContent. The examples below show that payload.

Authorization and read-only enforcement

The account is connected through Microsoft’s OAuth sign-in. Only work or school accounts can connect; Microsoft refuses a personal Microsoft account. The requested permissions are:
  • https://api.businesscentral.dynamics.com/Financials.ReadWrite.All
  • offline_access (keeps the connection alive)
Microsoft publishes no read-only delegated permission for the Business Central API, so the grant itself is read/write. Consile enforces read-only on its side:
  • The connector has no write tools.
  • Consile sends only read requests to the Business Central API.
  • The connect is rejected if Microsoft’s grant contains permissions beyond the Business Central API, offline_access and the standard sign-in scopes (openid, profile, email).
Since the Microsoft grant covers writes, Consile recommends connecting a Business Central user with a read-only permission set. Then Business Central itself also limits the access to reading. Access is renewed automatically. Consile never hands the token to the MCP client, and the MCP client’s own token is never forwarded to Microsoft.

Shared conventions

Environments and companies

Business Central addresses data by an environment name (a Production or Sandbox environment in the tenant) and a company id (a legal entity inside that environment). Both are per-call arguments; there is no stored default company. The intended order is list_environments (only when the default is wrong), then list_companies, then the company-scoped tools with the GUID in hand.
string
default:"Production"
Business Central environment name, 1 to 80 characters. Optional on every tool that takes it. Call list_environments if the tenant uses another name. An unknown name returns an error that lists the environments that exist.
string (GUID)
required
The company id from list_companies. Required on get_company_information and query_entity. It cannot be derived from a company name. A wrong GUID returns a 404 error, not another company’s data.
Optional case-insensitive substring filter (list_companies and list_entity_metadata). At least one character.

Result context

Every result except list_environments echoes a context object with the environment (and the companyId, where one applies) it was read from, so a result cannot be misattributed to another company. @odata.* annotation keys are removed from every row.

Typical call order

  1. list_companies (and list_environments only if the environment is not Production).
  2. get_company_information, to confirm which books are being read.
  3. list_entity_metadata, to see which entity sets the environment serves.
  4. query_entity with select and filter.

list_environments

Lists the Business Central environments in the connected Microsoft Entra tenant. Only Business Central environments are returned. Call it only when the tenant runs several environments or a tool reported an unknown environment name. Arguments: none.
array
Each item has name, type (Production or Sandbox), countryCode and aadTenantId (the Entra tenant id). A missing countryCode or aadTenantId is null.

list_companies

Lists the companies (legal entities) in an environment, with the GUID every company-scoped tool requires.
string
default:"Production"
string
Filters name and displayName case-insensitively.
array
Each item has id (the companyId), name, displayName and systemVersion.
boolean
true when a search matched more than one company. Ask the user which one is meant instead of guessing.

get_company_information

Reads a company’s own master data: registered name, address, VAT registration number (the CVR number in Denmark), currency code and the start of the current fiscal year. Use it to confirm which books you are reading before reporting numbers.
string
default:"Production"
string (GUID)
required
object | null
The company’s companyInformation record as Business Central returns it (for example displayName, addressLine1, city, postalCode, country, taxRegistrationNumber, currencyCode, currentFiscalYearStartDate), or null if the company has none.

list_entity_metadata

Lists the entity sets an environment exposes. Use the name values as the entity argument of query_entity. It is environment-level, so it takes no companyId: the same sets are served inside every company of that environment.
string
default:"Production"
string
Filters on name, case-insensitively.
array
Each item has name, kind, url and queryable. queryable: false means the set exists in the environment but is outside the allow-list query_entity accepts (for example companies, or a custom API page), so it cannot be read here.
A result larger than 40,000 JSON characters is refused. Pass search to narrow it.

query_entity

Reads one entity set of the standard Business Central API v2.0 with OData options, one page at a time, or one record by id. Only the 85 allow-listed entity sets can be read (see the list below).
string
default:"Production"
string (GUID)
required
string
required
Entity set name, 1 to 80 characters, letters and digits only (e.g. customers, salesInvoices, generalLedgerEntries). Matched case-insensitively against the allow-list. A name with any other character, or one outside the allow-list, is refused; an unknown name is answered with up to five closest matches.
string (GUID)
Reads one record instead of a page. filter, orderby and pageSize do not apply; select and expand do.
string
Raw OData $filter expression, 1 to 1,000 characters. String literals are single-quoted, with an embedded single quote doubled (displayName eq 'O''Brien'). Dates are written unquoted as YYYY-MM-DD (postingDate ge 2026-01-01); a quoted date is rejected by Business Central.
string[]
Field names for $select. Always pass it: Business Central rows are wide, and a page of full rows is likely to exceed the size cap.
string
$expand expression, 1 to 500 characters (e.g. dimensionSetLines). It multiplies the result size, so use it sparingly.
string
$orderby expression, 1 to 200 characters (e.g. postingDate desc).
integer
default:"50"
Rows per page, 1 to 500.
string
Opaque continuation token from a previous result’s nextCursor. Omit it for the first page and never construct or edit one.
array
The rows of the page, with only the selected fields.
string | null
Token for the next page, or null when the collection is exhausted. hasMore is true when a next page exists. There is no total count.
object
Returned instead of count/items/nextCursor/hasMore when id is given.

Paging

nextCursor is opaque. To read the next page, pass it back unchanged as cursor, together with the same environment, entity and companyId as the first call. The cursor continues the same query.

Size cap

A result larger than 100,000 JSON characters is refused, and the client sees only Tool invocation failed. Narrow select, add a filter or lower pageSize.

Allow-listed entity sets

accounts, accountingPeriods, agedAccountsPayable, agedAccountsReceivable, applyVendorEntries, approvalEntries, approvalUserSetups, attachments, balanceSheets, bankAccounts, cashFlowStatements, companyInformation, contacts, contactsInformation, countriesRegions, currencies, currencyExchangeRates, customers, customerContacts, customerFinancialDetails, customerPaymentJournals, customerPayments, customerReturnReasons, customerSales, defaultDimensions, dimensions, dimensionSetLines, dimensionValues, disputeStatus, documentAttachments, employees, fixedAssets, fixedAssetLocations, generalLedgerEntries, generalLedgerSetup, generalProductPostingGroups, incomeStatements, inventoryPostingGroups, items, itemCategories, itemLedgerEntries, itemVariants, jobQueueEntries, jobQueueLogEntries, journals, journalLines, locations, opportunities, paymentMethods, paymentTerms, pictures, postedApprovalEntries, projects, purchaseCreditMemos, purchaseCreditMemoLines, purchaseInvoices, purchaseInvoiceLines, purchaseOrders, purchaseOrderLines, purchaseReceipts, purchaseReceiptLines, retainedEarningsStatements, salesCreditMemos, salesCreditMemoLines, salesInvoices, salesInvoiceLines, salesOrders, salesOrderLines, salesQuotes, salesQuoteLines, salesShipments, salesShipmentLines, salespersonsPurchasers, shipmentMethods, subscriptions, taxAreas, taxGroups, timeRegistrationEntries, trialBalances, unitsOfMeasure, vendors, vendorPayments, vendorPaymentJournals, vendorPurchases, workflowApprovers.
companies is deliberately not on the list; use list_companies. A listed set can still be missing in a given environment, depending on localisation and version. list_entity_metadata shows what the environment actually serves. Custom API pages and extension APIs cannot be read.

connect_account

connect_account is a system tool that the Business Central endpoint lists next to the five tools. It takes no arguments and its name has no business-central__ prefix. It returns { "connect_url": "…", "instructions": "…" }. The user opens connect_url in a browser and is sent to Microsoft to sign in and approve access. The link expires after 10 minutes. It only works for accounts that subscribe to Business Central and for users who have accepted Consile’s terms in the portal. Use it to reconnect after the access expired or was removed: completing the link connects the account again with the new Microsoft sign-in.
Request

Errors

Tool failures come back as a normal tools/call result with isError: true and one text block, not as a JSON-RPC error. The connector returns explanatory messages for the common failures:

Limits

  • Business Central’s own budget: Microsoft allows 6,000 requests per 5 minutes per Business Central user, shared with every other Business Central client of that user. Narrow the filter instead of paging through everything.
  • Page size: default 50, maximum 500 rows.
  • Result size: 100,000 JSON characters for query_entity, 40,000 for list_entity_metadata.
Requests to the endpoint are also rate-limited per account and connector. When the limit is exceeded you get HTTP 429 (JSON-RPC error -32029, Retry-After: 1) instead of a tool result. See Errors & limits for the current limits and the protocol-level errors shared by all connectors.