Releases: SShadowS/business-central-mcp
Releases · SShadowS/business-central-mcp
Release list
v1.7.0
Added
- Central connection config. A
~/.bc-mcp/config.jsonc(orBC_MCP_CONFIG
/<cwd>/.bc-mcp.jsonc) file defines namedconnections, an optional
default, and an optionalmap[]from repo path to connection, so one
globally-registered server can serve multiple BC instances without a
BC_*env block per repo. Resolution order per field: an explicitBC_*
env var, thenBC_CONNECTION=<name>, then amap[]path match, then
default. Secrets can be kept out of the file with${ENV}references.
A<cwd>/.env(orBC_ENV_FILE) is also auto-loaded at startup
(override:false— real environment variables still win). With no config
file and no.envpresent, the server behaves exactly as before.
Full Changelog: v1.6.0...v1.7.0
v1.6.0
BC Online (SaaS) support: the server now runs against
businesscentral.dynamics.com as well as on-prem, with a password-free
sign-in for the UI tools and device-code OAuth for bc_query. On-prem
NavUserPassword is unchanged.
Added
- SaaS
/cshweb-client session (ESTS cookie). A portal URL
https://businesscentral.dynamics.com/{aadTenant}/{environment}selects
authMode: SaasWeb. The first UI tool opens a local127.0.0.1sign-in
window (password and MFA stay there — never in env, never in chat); portal
cookies persist underSTATE_DIR/saas-web-cookies.json(mode 0600, per
repo) and are reused across process restarts. The/cshWebSocket is
discovered on the cluster host after sign-in — no cluster URL in config. - OAuth / Microsoft Entra ID authentication for
bc_query. A SaaS portal
URL (orBC_AUTH=OAuth) acquires a Standard API token via device-code and
uses it asAuthorization: Bearerforbc_query. Refresh tokens are cached
underSTATE_DIR(mode 0600).BC_USERNAME/BC_PASSWORDare not required
in this mode. bc_queryno longer opens a/cshsession. The OData tool is
independent of the web-client WebSocket, so SaaS OAuth works for bulk reads
even when the first-party web-client cookie session cannot be established.- Device-code sign-in surfaces in chat. When
bc_queryneeds a sign-in it
fails fast withDEVICE_LOGIN_REQUIREDwhose message carries the
https://microsoft.com/devicelogin URL and user code (instead of blocking the
tool call and printing the code on stderr, which MCP clients never show).
The pending sign-in is persisted inSTATE_DIR/oauth-pending.json; retrying
the tool polls once and resumes — same code, no re-prompt — then runs the
query once sign-in is complete.BC_CLIENT_IDis required: a
publisher-owned multi-tenant public app (see README "bc_query on SaaS") —
customer tenants never register anything. Borrowed Microsoft first-party
clients fail at sign-in withAADSTS65002on hardened tenants. - SaaS URL parsing. A portal URL such as
https://businesscentral.dynamics.com/7bcb54ae-…/DEVis split into Entra
tenant + environment. OData is derived as
https://api.businesscentral.dynamics.com/v2.0/{tenant}/{environment}.
A verified AAD domain (contoso.onmicrosoft.com) is accepted in the tenant
segment as well as a GUID. npx business-central-mcp loginprimes the SaaS cookie file ahead of
the first tool call.
Changed
- Config: new
BC_AUTH,BC_AAD_TENANT_ID,BC_ENVIRONMENT,BC_OAUTH_SCOPE,
BC_CLIENT_ID.BC_USERNAME/BC_PASSWORDare required only for
NavUserPassword; a SaaS password in env is ignored. - Session-lifecycle hardening. A dead or revoked SaaS session is detected
and reopens interactive sign-in via a windowed, episode-based escalation
(transient outages never destroy valid cookies; a brief portal interstitial
during backoff never escalates; a genuinely dead session does). A fresh
sign-in is verified behaviorally — signing in with the wrong Microsoft
account or tenant fails with a clear, non-retryable error and saves nothing,
instead of silently degrading into repeat prompts. A session revoked while
the cluster tab is bound now recovers instead of wedging. - HTTP route-gating. Unknown REST paths
404and non-POST/mcp405
before any BC session is created, so a stray request (a LAN scanner's
GET /favicon.ico) can no longer trigger session creation or pop the
interactive SaaS sign-in window. Sign-in-flow errors on the REST path now
carry their code and payload (verification URL, user code) instead of an
opaque500.
Fixed
bc_queryOData errors preserve their typed BC error (code + hint) instead
of collapsing aDEVICE_LOGIN_REQUIREDinto a generic network error.- Cookie handling:
Set-Cookiedeletions (Max-Age=0/ pastExpires) are
honored per RFC 6265; cookies scoped to a bare public suffix are rejected;
the portal auth cookie is matched by resolved-GUID suffix so domain-form
tenants work; the SaaS cluster host is allow-listed todynamics.com. - OAuth token refresh is single-flighted, so concurrent
bc_querycalls at
token expiry share one grant instead of racing and wiping the cache; a
captive-portal non-JSON200during device-code polling no longer churns
the pending code.
What's Changed
- docs: upgrade VSCode install badge to prompt for credentials via inputs by @SShadowS in #6
- docs: document BC_APPLICATION_ID=NAV for on-prem containers by @SShadowS in #11
- feat(saas): BC Online /csh web-client session (ESTS) by @FBakkensen in #12
- fix(saas): PR #12 review follow-ups (#11-16 hardening/cleanup) by @SShadowS in #13
- feat(saas): session-lifecycle hardening — escalation, sign-in verification, warm-path recovery by @FBakkensen in #15
- docs: correct the bc_query SaaS error-path description by @SShadowS in #16
New Contributors
- @SShadowS made their first contribution in #6
- @FBakkensen made their first contribution in #12
Full Changelog: v1.5.0...v1.6.0
v1.5.0
Added
- Multi-row selection.
bc_execute_actionacceptsbookmarks: string[]to
select N rows and invoke a selection-consuming action (Delete) over the whole
set atomically (SetCurrentRowAndRowsSelection+InvokeActionin one queue
entry). The anchor isbookmarks[0]and must be a member of the set. Only
selection-consuming actions act on all rows; Edit/View/DrillDown/New are
current-row-only and are rejected withbookmarks[]. A stale anchor returns
INVALID_BOOKMARK;BC_MAX_SELECTION(default 100) caps the set. - Generic file download capture.
bc_execute_action,bc_respond_dialog,
bc_wizard_navigate, andbc_run_reportnow returndownloads: Download[]
(inline base64 + optional disk write) andexternalUris[]via a shared
DownloadService. Only same-origin URLs under an allowlisted BC file path are
fetched (SSRF/credential-leak guard); external andmailto:URIs are surfaced
but never dereferenced. Per-file/aggregate/count caps andBC_DOWNLOAD_DIR
are configurable. - Config.
BC_MAX_SELECTION; download limitsBC_MAX_DOWNLOAD_BYTES,
BC_MAX_DOWNLOAD_TOTAL_BYTES,BC_MAX_DOWNLOADS,BC_DOWNLOAD_DIR
(falls back toBC_REPORT_DIR).
Changed
- BREAKING (
bc_run_report): the singulardownloadfield is replaced by
downloads: Download[]for parity with the other download-capturing tools. - Default client version / serverMajor now default to BC28.
Fixed
- BC 28.3
/csh403. The WebSocket upgrade now sends anOriginheader, so
BC 28.3'sRequestOriginValidationMiddlewareno longer rejects the connection.
Same-origin only; a no-op on BC 28.0. - Multi-row action silent no-op. A multi-row Delete on a page that forbids it
(e.g. the Customer list) previously returned success with nothing deleted. BC
disables such actions server-side (Enabled=false);bc_execute_actionnow
detects that and returnsMULTI_ROW_ACTION_UNAVAILABLEinstead of a lying
success. Where BC keeps the action enabled it deletes all selected rows. - Download disk-write filenames are sanitized against path traversal.
Full Changelog: v1.4.0...v1.5.0
v1.4.0
v1.3.0
v1.1.0
v1.0.2
Full Changelog: https://github.com/SShadowS/business-central-mcp/commits/v1.0.2