Business Central MCP
MCP server for Microsoft Dynamics 365 Business Central via reverse-engineered WebUI protocol. Enables AI assistants like Claude to interact with BC through the native WebSocket interface.
Ask AI about Business Central MCP
Powered by Claude Β· Grounded in docs
I know everything about Business Central MCP. Ask me about installation, configuration, usage, or troubleshooting.
0/500
Reviews
Documentation
business-central-mcp
Give AI assistants direct access to Microsoft Dynamics 365 Business Central.
Native WebSocket protocol -- no OData, no APIs, no browser automation.
Overview
| Property | Value |
|---|---|
| Language | TypeScript / Node 20+ |
| npm package | business-central-mcp |
| BC versions | BC27, BC28 (wire-compatible) |
| Auth | NavUserPassword (OAuth on roadmap) |
| Tools | 12 |
| Tests | 284 unit/protocol + 111 integration |
| License | MIT |
Install
VSCode
Click the badge. VSCode opens, prompts to add the server, and writes to your user mcp.json.
You will still need to set BC_BASE_URL, BC_USERNAME, and BC_PASSWORD in the entry's env block. VSCode opens the file for you to edit.
Manual install
Workspace: create .vscode/mcp.json:
{
"servers": {
"business-central": {
"command": "npx",
"args": ["-y", "business-central-mcp"],
"env": {
"BC_BASE_URL": "http://your-bc-server/BC",
"BC_USERNAME": "your-user",
"BC_PASSWORD": "your-password"
}
}
}
}
Claude Code
claude mcp add business-central \
-e BC_BASE_URL=http://your-bc-server/BC \
-e BC_USERNAME=you \
-e BC_PASSWORD=secret \
-- npx -y business-central-mcp
Scope it to the current project with --scope project. See claude mcp --help for scoping options.
Claude Desktop
- Download the latest
.dxtfrom Releases. - Double-click. Claude Desktop opens Settings β Extensions and prompts for BC URL, username, and password.
- Restart Claude Desktop.
Manual install
Edit claude_desktop_config.json:
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json - Windows:
%APPDATA%\Claude\claude_desktop_config.json - Linux:
~/.config/Claude/claude_desktop_config.json
{
"mcpServers": {
"business-central": {
"command": "npx",
"args": ["-y", "business-central-mcp"],
"env": {
"BC_BASE_URL": "http://your-bc-server/BC",
"BC_USERNAME": "your-user",
"BC_PASSWORD": "your-password"
}
}
}
}
Restart Claude Desktop.
Configuration
| Variable | Required | Default | Description |
|---|---|---|---|
BC_BASE_URL | Yes | β | BC server base URL, e.g. http://your-bc-server/BC |
BC_USERNAME | Yes | β | NavUserPassword username |
BC_PASSWORD | Yes | β | NavUserPassword password |
BC_PROFILE | No | server default | Profile id, e.g. BUSINESS MANAGER. Affects which Role Center loads and which pages Tell Me indexes. |
BC_TENANT_ID | No | default | Multi-tenant deployments only. |
BC_CLIENT_VERSION | No | 27.0.0.0 | Version reported to BC during session open. |
PORT | No | 3000 | HTTP transport port (stdio transport ignores this). |
LOG_LEVEL | No | info | debug / info / warn / error. |
LOG_DIR | No | ./logs | Directory for log files. |
STATE_DIR | No | ./.state | Directory for session state. |
BC_INVOKE_TIMEOUT | No | 30000 | Per-invoke timeout in ms. Kills hung sessions. |
BC_RECONNECT_MAX_RETRIES | No | 4 | Reconnect attempts after session death. |
BC_RECONNECT_BASE_DELAY | No | 1000 | Base delay (ms) for exponential reconnect backoff. |
What can it do?
| Tool | What it does |
|---|---|
bc_open_page | Open any page by ID -- lists, cards, documents, role centers. Returns the page as sections[] with header, lines, factboxes, and Role Center cuegroup tiles. |
bc_read_data | Refresh a single section: filter, paginate, slice, project tab/columns. Returns the same Section shape as bc_open_page. |
bc_write_data | Write field values; BC validates and echoes confirmed values. Section-aware (lines, factboxes, header). |
bc_execute_action | Run header / row / wizard actions, OR drill down on Role Center cue tiles via cue input. |
bc_respond_dialog | Handle confirmation prompts and request pages |
bc_navigate | Select rows, drill down into records, field lookups |
bc_search_pages | Tell Me search. Returns { name, objectType, runTarget, departmentPath, category, score } per result. |
bc_close_page | Close a page and free server resources |
bc_switch_company | Switch to a different company mid-session |
bc_list_companies | Discover available companies |
bc_run_report | Execute reports and fill request page parameters |
bc_wizard_navigate | Drive NavigatePage / wizard flows (back / next / finish / cancel) |
How it works
This server speaks BC's internal WebSocket protocol directly -- the same protocol the browser-based web client uses. It was reverse-engineered from decompiled BC server assemblies. No OData endpoints, no SOAP services, no Selenium.
One WebSocket connection per session. All operations serialized through a promise queue. BC27 and BC28 are wire-compatible.
LLM (Claude / Copilot / etc.)
|
v MCP (stdio or HTTP)
business-central-mcp
|
v WebSocket + JSON-RPC
BC Web Service Tier (BC27 / BC28)
|
v internal calls
BC Server
Page output shape
bc_open_page returns the page as a flat list of sections:
{
"pageContextId": "session:page:21:abc",
"pageType": "Card",
"caption": "Customer Card",
"isModal": false,
"sections": [
{ "sectionId": "header", "kind": "header", "fields": [...], "actions": [...] },
{ "sectionId": "factbox:Customer Statistics", "kind": "factbox", "fields": [...] }
]
}
Each section carries its own content shape:
- Card-style (
headeron Card pages,factbox,requestPage):fields[]and (forheader)actions[] - List-style (
lineson Documents,headeron List pages, repeater subpages):rows[]andtotalRowCount - Cue tiles (Role Center hosted CardParts):
cues[]with each tile'sname,value,groupCaption,synopsis,hasAction. Drill down withbc_execute_action { section, cue }.
bc_read_data returns a single Section for the requested sectionId (defaults to "header"). The section ID for a FactBox or subpage comes from the bc_open_page response.
Session resilience
- Automatic reconnect with exponential backoff after session death
- Handles BC's ~15s NTLM auth slot hold after crashes
- Auto-dismisses license popups on fresh databases
- Invoke timeout kills hung sessions and triggers recovery
- Auto-recovery from
LogicalModalityViolationExceptionmid-session: reconciles the modal stack and retries transparently; falls back to session reset when BC keeps a confirm dialog sticky
Key files
| File | Purpose |
|---|---|
src/stdio-server.ts | npm bin entry -- stdio MCP transport |
src/server.ts | HTTP MCP transport entry |
src/mcp/ | MCP tool registry, schemas, request handler |
src/operations/ | One handler per tool (bc_open_page, bc_read_data, etc.) |
src/services/ | Page, data, action, navigation, search business logic |
src/protocol/ | WebSocket transport, wire types, captures |
src/session/ | Session lifecycle, modal stack, reconnect |
manifest.json | Claude Desktop Extension manifest |
scripts/build-dxt.ts | Builds .dxt artifact for Claude Desktop |
.github/workflows/release.yml | Builds + attaches .dxt on v* tag pushes |
ROADMAP.md | Deferred work (OAuth, Cursor, init wizard) |
Development
git clone https://github.com/SShadowS/business-central-mcp
cd business-central-mcp
npm install
npm run start:stdio-direct # Run from source
npm test # 284 unit + protocol tests
npm run test:integration # 111 integration tests against real BC (requires running BC server)
Roadmap
OAuth, Cursor support, an interactive init wizard, and a few protocol gaps.
See ROADMAP.md for the full list and priorities.
Author: Torben Leth (sshadows@sshadows.dk) License: MIT (see LICENSE)
