Skip to content

v26.1.10

Pre-release
Pre-release

Choose a tag to compare

@baramundi-bwiedemann baramundi-bwiedemann released this 07 Oct 22:12
cb9d1cd

Breaking for anyone who calls tools by name: the endpoint and groups tools are merged into
one tool per operation (#174), and while writes are off the tool list shows only read tools
(#156). See "Upgrading from 26.1.9" below and the old → new tool tables under Changed. With
the default settings (writes off) all 13 servers together list 130 tools with about 134 KB of
tool definitions on bMS 26R1 (26.1.9: 276 tools, 234 KB) and 100 tools, about 105 KB, on 25R2
(26.1.9: 240 tools, 206 KB): 43 % and 49 % less context per session.

Added

  • List tools can answer "how many?" without loading a page. Every list tool that pages its results
    accepts countOnly: true: the tool asks bConnect for a single row with the same filters and returns
    only totalItems and the filters it applied. Against the bConnect mock, counting Windows endpoints
    takes 17 bytes instead of 8.8 KB for a page of 10. If the answer has no numeric total, the result says
    the count is unavailable rather than guessing. countOnly is handled by the server and never sent to
    bConnect. Which tools offer it is derived from the API specification (123 tools on bMS 26R1, 111 on
    25R2); it adds about 9.8 KB to the tool list on 26R1. Not breaking: without countOnly every tool
    behaves as before.
  • Every tool tells clients whether it only reads or can destroy data. Each tool in tools/list
    now carries MCP annotations: a readable title ("List Windows endpoints by logical group"),
    readOnlyHint, and on tools that change something destructiveHint. A tool that only reads is
    marked read-only; a tool that deletes, or whose effect can't be undone (for example running a job,
    replacing a BitLocker PIN or cleaning up managed-software files), is marked destructive. Clients
    can use this to run reads without asking and to ask before destructive calls. The hints are
    derived from the bConnect operations each tool calls, and a test checks them against the API
    specification for both bMS releases. They are hints only: the write and secret gates
    (ALLOW_WRITE_OPERATIONS, ALLOW_SECRET_READ) are unchanged and still decide what a tool may do.

Changed

  • One Express major: 5. Each server's own HTTP mode (MCP_TRANSPORT=http) now runs on Express 5,
    as the gateway and the MCP SDK already did; the suite installs a single Express (5.2.1), and the
    manifests and type definitions say so. The gateway already ran Express 5.2.1 in every build while
    its manifest still named Express 4. Its separate package-lock.json, which no build used, is
    removed: the gateway runs on the root install (#69). Not breaking: the HTTP mode answers as before
    (tool calls, malformed JSON, host check), and a request that fails inside the handler now gets a
    JSON-RPC "Internal error" instead of being able to stop the server process.

  • Maintenance windows follow the bMS release. On bMS 2025 R2 the create tools offered the 2026 R1
    window types: their default, Anytime, and Never don't exist in 25R2, and 25R2's Unrestricted
    was missing (#307). Creating a maintenance window now offers and accepts the selected release's
    types and applies its interval rule: on 25R2 Unrestricted (the default, no intervals),
    Everyday, WorkdayWeekend and IndividualWeekday; on 26R1 the same types as before.
    Unrestricted, which the 26R1 specification marks deprecated, isn't offered there: a call with
    it, which used to be passed on, is now refused with "use Anytime". A type the release doesn't have
    is refused before anything is sent. Updating a maintenance window still needs 26R1: 25R2 updates with PUT, and its
    API specification describes that request in two contradicting ways, so it isn't offered until a
    25R2 bMS confirms it. Not breaking: on 26R1 the tool list is unchanged.

  • A server whose APIs the bMS release lacks says so at startup. Started against a bMS 2025 R2,
    the compliance and universaldynamicgroups servers stopped with cannot reach bConnect API … Check BCONNECT_BASE_URL, credentials, and network., although the bMS was reachable: their APIs exist
    only in 26R1 (#310). They now stop before the connectivity check, also when it is skipped, with one
    line that names the release they need and the one in use, for example bconnect-compliance-mcp: needs bMS 26R1; this server uses 25R2 (detected: bMS 25.2.0.0). None of its APIs exist in that release. Which release a server needs comes from its generated release table. On 26R1, and for
    the other 11 servers, nothing changes; the HTTP gateway still serves both domains with empty tool
    lists on 25R2. Not breaking.

  • Breaking: the endpoint and groups tools are one tool per operation, with the type as an argument.
    The endpoints server had a copy of each operation per device type; the copies are merged into one
    tool with a type argument (#174). Its values are the API's endpoint type names, the same as the
    type field of the results: WindowsEndpoint, MacEndpoint, LinuxEndpoint, AndroidEndpoint,
    IOSEndpoint, NetworkEndpoint, and IndustrialEndpoint on bMS 25R2 only. The tool list offers
    only the values the bMS release has; a filter or field that only some types take says which, and a
    call that combines it with another type is refused before anything is sent. Each call sends the
    same request as the old tool did. The old names are not kept as aliases: calling one returns the
    replacement, for example list_windows_endpoints was replaced by list_endpoints: call list_endpoints with type "WindowsEndpoint". One difference: updating an Android or iOS endpoint without any field
    is now refused, as for the other types (it sent an empty change before). Create tools stay per
    type, because their required fields differ. The endpoints server lists 32 tools on 26R1 (61
    before) and 25 on 25R2 (58); its tool list shrinks from 50.9 KB to 32.1 KB on 26R1 (writes off:
    21.8 KB to 9.1 KB).

    Old tool New call
    list_windows_endpoints, list_mac_endpoints, list_linux_endpoints, list_android_endpoints, list_ios_endpoints, list_network_endpoints, list_industrial_endpoints list_endpoints with type WindowsEndpoint, MacEndpoint, LinuxEndpoint, AndroidEndpoint, IOSEndpoint, NetworkEndpoint, IndustrialEndpoint
    search_endpoints (query, pageSize) list_endpoints without type, with SearchQuery and PageSize (it sent PageSize 50 when none was given; pass it to keep that)
    get_windows_endpoint, get_mac_endpoint, get_linux_endpoint, get_android_endpoint, get_ios_endpoint, get_network_endpoint, get_industrial_endpoint get_endpoint with type (as above)
    delete_windows_endpoint, delete_mac_endpoint, delete_linux_endpoint, delete_android_endpoint, delete_ios_endpoint, delete_network_endpoint, delete_industrial_endpoint delete_endpoint with type (as above)
    update_windows_endpoint, update_mac_endpoint, update_linux_endpoint, update_android_endpoint, update_ios_endpoint, update_network_endpoint, update_industrial_endpoint update_endpoint with type (as above)
    start_windows_enrollment, start_mac_enrollment, start_android_enrollment, start_ios_enrollment start_enrollment with type WindowsEndpoint, MacEndpoint, AndroidEndpoint, IOSEndpoint
    list_group_endpoints list_endpoints_by_logical_group without type
    list_windows_endpoints_by_logical_group list_endpoints_by_logical_group with type WindowsEndpoint

    list_endpoints, get_endpoint, delete_endpoint and list_endpoints_by_logical_group without
    type work as before.

    The groups server had a tool per group kind and member type; its 33 tools are now two (#174):
    list_group_members with groupKind (LogicalGroup, StaticGroup, DynamicGroup,
    UniversalDynamicGroup), groupId and, optionally, memberType (an endpoint type as above, or
    LogicalGroup for the child groups of a logical group; left out: all endpoints), and
    list_ad_user_endpoints with adUserId and, optionally, endpointType. groupId replaces
    logicalGroupId, staticGroupId, dynamicGroupId and universalDynamicGroupId. A combination
    the API has no route for is refused with the valid ones, for example list_group_members has no route for groupKind "DynamicGroup" and memberType "MacEndpoint". Valid on bMS 26R1: groupKind "DynamicGroup" without memberType; groupKind "DynamicGroup" and memberType "WindowsEndpoint".
    Each call sends the same request as the old tool did, with the same filters, includeSubfolders
    (logical groups) and countOnly. An old name returns its replacement, for example
    list_mac_endpoints_by_static_group was replaced by list_group_members: call list_group_members with groupKind "StaticGroup" and with memberType "MacEndpoint", with groupId (was staticGroupId).
    The groups server lists 2 tools in both releases (30 before on 26R1, 33 on 25R2); its tool list
    shrinks from 44.4 KB to 6.1 KB on 26R1 and from 47.6 KB to 5.4 KB on 25R2. The four
    assign_job_to_* tools now say to check their reach with list_group_members and
    countOnly: true instead of PageSize: 1.

    Old tool New call
    list_endpoints_by_logical_group (groups server; logicalGroupId) list_group_members with groupKind LogicalGroup, without memberType, groupId
    list_windows_endpoints_by_logical_group, list_mac_endpoints_by_logical_group, list_linux_endpoints_by_logical_group, list_android_endpoints_by_logical_group, list_ios_endpoints_by_logical_group, list_network_endpoints_by_logical_group, list_industrial_endpoints_by_logical_group list_group_members with groupKind LogicalGroup and memberType WindowsEndpoint, MacEndpoint, LinuxEndpoint, AndroidEndpoint, IOSEndpoint, NetworkEndpoint, IndustrialEndpoint; groupId
    list_logical_groups_by_logical_group list_group_members with groupKind LogicalGroup and memberType LogicalGroup; groupId
    list_endpoints_by_static_group (staticGroupId) list_group_members with groupKind StaticGroup, without memberType, groupId
    list_windows_endpoints_by_static_group, list_mac_endpoints_by_static_group, list_linux_endpoints_by_static_group, list_android_endpoints_by_static_group, list_ios_endpoints_by_static_group, list_network_endpoints_by_static_group, list_industrial_endpoints_by_static_group list_group_members with groupKind StaticGroup and memberType (as above); groupId
    list_endpoints_by_dynamic_group (dynamicGroupId) list_group_members with groupKind DynamicGroup, without memberType, groupId
    list_windows_endpoints_by_dynamic_group list_group_members with groupKind DynamicGroup and memberType WindowsEndpoint; groupId
    list_endpoints_by_universal_dynamic_group (universalDynamicGroupId) list_group_members with groupKind UniversalDynamicGroup, without memberType, groupId
    list_windows_endpoints_by_universal_dynamic_group, list_mac_endpoints_by_universal_dynamic_group, list_linux_endpoints_by_universal_dynamic_group, list_android_endpoints_by_universal_dynamic_group, list_ios_endpoints_by_universal_dynamic_group, list_network_endpoints_by_universal_dynamic_group, list_industrial_endpoints_by_universal_dynamic_group list_group_members with groupKind UniversalDynamicGroup and memberType (as above); groupId
    list_endpoints_by_ad_user list_ad_user_endpoints without endpointType
    list_windows_endpoints_by_ad_user, list_mac_endpoints_by_ad_user, list_linux_endpoints_by_ad_user, list_android_endpoints_by_ad_user, list_ios_endpoints_by_ad_user list_ad_user_endpoints with endpointType WindowsEndpoint, MacEndpoint, LinuxEndpoint, AndroidEndpoint, IOSEndpoint

    The industrial member type exists only on bMS 25R2, as before. All 13 servers on 26R1 now list
    211 tools (239 before this change, 268 before #174), 130 with writes off (158, 173).

  • Each bMS release lists only the tools whose API routes it has. Which tools a release offers
    is now derived from its API specification instead of hand-written checks: a tool is listed when
    every route it calls exists in the release. This hides tools that could only fail: the 8
    compliance tools and the 2 maintenance-window update tools on 25R2 (25R2 updates with PUT, the
    tools send PATCH; #307), and the 8 industrial-endpoint tools on 26R1, whose API was removed.
    26R1 lists 268 tools (173 with writes off), 25R2 230 (148). A tool called by name on a release
    that lacks it answers <tool> is only available in bMS <release>; this server uses <release> (…).
    Not breaking: the hidden tools didn't work on those releases.

  • The servers read the bMS release from the bMS at startup. Each server, and the gateway with
    its service credential, asks the bMS for its version once at startup (26.1.… is 26R1, 25.2.…
    is 25R2) and logs the release it uses, for example bMS 26.1.161.0 → release 26R1. That release
    selects the tools, list filters and error explanations, as BCONNECT_RELEASE did before.
    BCONNECT_RELEASE is now the fallback: it applies when the version can't be read (for example an
    account without read access to server management) or is not a known release, with a warning that
    says why. A BCONNECT_RELEASE that differs from the detected release is overridden, with a warning.
    BCONNECT_SKIP_CONNECTIVITY_CHECK=true skips the detection too. A tool the release doesn't offer
    now answers <tool> is only available in bMS 26R1; this server uses 25R2 (…) instead of telling
    you to set BCONNECT_RELEASE. Not breaking: with a correct BCONNECT_RELEASE, nothing changes.

  • Breaking: while writes are off, the tool list shows only read tools. With
    ALLOW_WRITE_OPERATIONS not set to true (the default, and always in the gateway), tools/list
    leaves out every tool that creates, changes, deletes or starts something. Every MCP client loads
    the whole tool list into the model's context, so this saves 98 tools and 77 KB on bMS 26R1
    (276 → 178 tools, about 22,000 tokens or 29 % per session) and 84 tools and 67 KB on 25R2
    (240 → 156, about 19,000 tokens, 29 %). Which tools are left out is derived from the bConnect operations each tool
    calls, the same classification as the tool annotations. With ALLOW_WRITE_OPERATIONS=true the
    list is unchanged. A write tool called by name is still refused with the same message as before;
    the refusal stays the control. Who is affected: a client or workflow that pre-approved or
    selected write tools by name doesn't see them while writes are off. Set
    ALLOW_WRITE_OPERATIONS=true where writes are wanted and reconnect the client.

  • Tool results are compact JSON. Results carry the same data without indentation, which keeps
    16–22 % of each result out of the model's context (measured on list results against the bMS 26R1
    mock, e.g. list_endpoints 28.4 KB → 23.5 KB). Lead lines such as "Network endpoint … updated:"
    and error messages are unchanged. Consumers that parse the JSON see no difference; if you compare
    result text, set the new BCONNECT_PRETTY_JSON=true to get the earlier indented format. The
    setting accepts true or false; any other value stops the server and the gateway.

  • Every pull request is tested against the bConnect mock, for bMS 26R1 and 25R2. The
    mock-integration tests, which send each server's requests to bConnect-Mock's real routes and
    fixtures, ran only by hand. CI now runs them in a mock job, once per release, against a pinned
    mock version (26R1: all 13 servers; 25R2: the 11 whose APIs exist there). A run where the mock
    wasn't reachable fails instead of passing untested. By hand: node scripts/mock-tier.mjs 26r1
    (docs/MOCK_INTEGRATION_TESTING.md).

Fixed

  • The gateway answers request errors with JSON-RPC, not an HTML page. A request body that isn't
    valid JSON now gets HTTP 400 with the JSON-RPC error -32700 "Parse error", as each server's own
    HTTP mode already answered; a body over MCP_GATEWAY_MAX_BODY gets 413 and an unsupported charset
    or encoding 415, all other request errors keep their status, with -32603 "Internal error". A path
    the gateway doesn't serve gets a JSON 404 ({"error":"Not found"}), and so does an OPTIONS
    request (the gateway offers no CORS; it used to answer with a list of allowed methods). The other
    answers (unknown domain, 405, rate limit, host check) are unchanged. A request that fails with a
    5xx is now logged. The gateway and the servers share one handler for these errors.

Upgrading from 26.1.9

  • Calls to endpoint or groups tools by their old names fail. Replace them as listed under
    Changed (for example list_windows_endpoints → list_endpoints with type WindowsEndpoint,
    list_endpoints_by_static_group → list_group_members with groupKind StaticGroup). Saved
    prompts, skills and automation that name tools need the new names.
  • Write tools are no longer listed while writes are off. Before, they were listed and refused
    when called. If a client or automation needs them, set ALLOW_WRITE_OPERATIONS=true for that
    server. The gateway keeps writes off, as before.
  • If you compare result text, set BCONNECT_PRETTY_JSON=true to keep the indented format.
  • BCONNECT_RELEASE is only a fallback now: each server reads the release from the bMS at
    startup, and that release wins (with a warning if BCONNECT_RELEASE says otherwise).
    BCONNECT_RELEASE applies when the version can't be read, for example for an account without
    read access to server management.
  • On a bMS 2025 R2, remove the compliance and universal dynamic groups servers from your client
    configuration: they stop at startup with "needs bMS 26R1". The maintenance-window update tools
    are not offered on 25R2.

Known issues

  • The gateway has no built-in authentication. Front it with an authenticating, TLS-terminating
    reverse proxy that also checks Host and Origin.
  • The gateway has no trust-proxy setting. Behind a proxy it sees every request as coming from
    the proxy, so all callers share one rate-limit bucket and the access log shows the proxy's address.
  • Some reads are slow on a large or busy bMS and can run into the default 30 s timeout; set
    BCONNECT_TIMEOUT_MS=90000 for those servers (see docs/TROUBLESHOOTING.md).