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). More curated read tools are planned. 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 connect flow is a standard authorization-code flow with PKCE against https://login.microsoftonline.com/organizations/oauth2/v2.0/authorize. Because it uses the organizations endpoint, only work or school accounts can connect; a personal Microsoft account fails at Microsoft. The requested scopes are:
  • https://api.businesscentral.dynamics.com/Financials.ReadWrite.All
  • offline_access (for the refresh token)
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. Reads ask for Business Central’s read-only data access intent (Data-Access-Intent: ReadOnly), which routes them to a read replica. If an API page answers 400 to that, the request is retried once without it.
  • The granted scope is checked as a closed set when the account is connected. It must contain a Business Central API scope (Financials.ReadWrite.All or user_impersonation, qualified or bare). openid, profile, email and offline_access are tolerated. Any other scope rejects the connect, and so does a token response without a refresh token.
Since the Microsoft grant covers writes, Consile recommends connecting a Business Central user with a read-only permission set. The user’s own Business Central permissions are the only layer that also limits the token outside Consile. Access tokens are refreshed 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. Nothing about the choice is stored on Consile’s side. 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, applied by Consile after the read (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. The tool description tells the model to 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, read from its OData service document. 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 before any request is made; 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

Paging is server-driven. Pass the nextCursor back as cursor to read the next page. The cursor carries the original query, so environment, filter, select, expand and orderby are ignored on a continuation, and pageSize applies to the next page. entity and companyId are still required and validated, so pass the same values again. A cursor is only accepted if it points back to the Business Central API; anything else returns an Invalid cursor error. If you pass both id and cursor, the cursor is used.

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. Calling it on an account that is already connected replaces the stored Microsoft access, which is how you reconnect after the access expired or was removed.
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 checks run in this order: tool name, subscription, seat, connection, then argument validation and the call to Business Central. Business Central is one of the connectors that returns explanatory messages for the common upstream failures:

Limits

  • Timeout: each request to Business Central times out after 30 seconds.
  • Throttling: a 429 from Business Central is retried once, after its Retry-After (at most 5 seconds, 1 second if none is given).
  • 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.