Neither of the bridge's two "clear sessionId and reinitialize" paths ever
told BC the old session was actually done - they just drop the local
sessionId variable and let a fresh session get issued on the next call.
The MCP Streamable HTTP transport spec defines an explicit way to end a
session: an HTTP DELETE to the endpoint carrying the session's
Mcp-Session-Id. The bridge has never called it.
Trying this as a candidate fix for the recurring Internal_CompanyNotFound
pattern documented in bc-mcp-company-header-must-match-exact-company-name.md:
a client-side session reset (clear sessionId + reinitialize) does NOT clear
the error, but a manual save on the BC-side MCP Server Configuration record
does. If BC's server-side session state is what's actually stuck, an
explicit close might do the same job the manual config-save has been doing
by accident.
Committed before live-testing (not after) specifically so it survives the
next sync-bcquality-knowledge.ps1 run instead of being silently overwritten
from the old source - this is a durability commit, not a confirmed-fix
commit. Best-effort and silent on failure: if BC responds 404/405 (DELETE
not implemented), that's evidence for the MS support escalation, not a bug
here. Update this commit's status (confirmed working / confirmed no effect
/ reverted) once tested against a live recurrence.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
New follow-up section, distinct from the 2026-08-03 "ruled out" static
verification (Aktiv/Standard confirmed on, unchanged). This is about the
save/toggle *action* on CURABIS_DEV's MCP Server Configuration page, not
its resting state - not previously tested.
Observed 2026-08-07 (MID): Internal_CompanyNotFound recurred. VS Code
restart + retry failed (consistent with the already-falsified restart
theory). Toggling the Standard field on CURABIS_DEV and saving, then
retrying, worked immediately. MID reports having seen this same pattern -
restart-retry fails, config-touch-retry succeeds - on prior occasions.
Framed explicitly as a candidate, not a confirmed fix: n>=2 informal
observations, toggle direction untested (MID's own read is that direction
is probably irrelevant, pointing at the save/republish action busting a
server-side cache rather than at the field's value), and no baseline
established against the error's already-documented intermittency. Does
not override the Microsoft-support-escalation guidance - if anything it's
supporting evidence for that escalation, since a CURABIS-side config touch
masking a BC-side symptom points at BC's MCP session/cache layer.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Two fixes bundled together, both diagnosed from a live BC MCP failure in
a Jernpladsen (Project Management 365) session:
- 2026-08-05 (previously drafted, never committed): BC rejects a
non-initialize request with a stale/absent Mcp-Session-Id with "A new
session can only be created by an initialize request." The prior retry
just cleared sessionId and resent the same message with no header,
reproducing the identical error. Now replays the client's cached
initialize message first to obtain a fresh session, then retries.
This also fixes dispatchCreateComment's per-chunk fresh-session reset,
which was hitting exactly this failure on every chunk of a >250-char
Task Comment.
- 2026-08-07: the reactive fix above only self-heals after BC has
already rejected a request. A client that opens a fresh session per
call (e.g. a Power Automate flow) never hits staleness at all, which
is why that pattern reads as more reliable than our long-lived
interactive bridge process. Added a proactive refresh: if the cached
session has been idle past a heuristic threshold, re-initialize
before attempting the call instead of waiting for the rejection.
Promotes rules that are already published in community/ to custom/knowledge/,
so they load at every session start instead of only on keyword relevance.
Each file carries extends: pointing back to its community source.
Passed Immanuel's four-test Categorical Imperative validation on 2026-08-07.
Neither fetch() call had a timeout, and the BC session (Mcp-Session-Id)
plus the underlying HTTP connection were reused for the bridge process's
entire lifetime with no proactive refresh. A long-running Claude Code
session with gaps between calls can leave either stale.
Observed today: a 30-minute hang on one call (no timeout meant it never
failed on its own), and separately an "Internal_CompanyNotFound" on two
machines that likely wasn't a real company problem but a dead session --
Michael noticed the pattern independently: Summatim's frequent quick calls
never have this issue, longer sessions with gaps do.
Added REQUEST_TIMEOUT_MS (30s) via AbortSignal.timeout on both fetch
calls, and wrapped forward() to retry once with sessionId cleared on any
failure -- self-heals a stale session/connection without the developer
noticing. Tested end to end: full initialize + tools/call succeeds
normally (no retry needed), and a forced-failure path correctly retries
once then surfaces the real error if it persists.
Type B gap (Francis): bc-mcp-bridge.js is a Node.js script and the
businesscentral MCP registration launches it via 'node ...', but nothing
in the setup checklist ever verified Node was actually installed. Found
missing on a fresh machine during a full developer onboarding today --
the bridge deployed fine, the MCP server registered fine, and then every
connection attempt would have failed with a generic timeout instead of a
clear "Node missing" message.
Checked first: this is genuinely uncovered, not a documentation-clarity
issue -- ~/.bc-mcp.config.json's path is already stated unambiguously
everywhere it's referenced, so no rule needed there. This is a different,
real gap: no prerequisite check existed at all.
Observed live: a consultant hit "no" reflexively on a setup confirmation
while moving fast through onboarding, and only noticed afterward. Most
of this document's ja/nej gates aren't real choices -- the standard is
company policy, not a per-developer preference -- and a blocking
question with only one sane answer just invites that kind of misclick.
v24 -> v25. Converted to act-and-report (no question) wherever the file
is git-tracked and the replacement is already verified correct: the
v6-era repo-mirror cleanup, CLAUDE.md's obsolete-forms replacement, and
the v24 migration's repo-local agent-file / find-altool.ps1 removal --
all fully recoverable via git revert if anyone ever wants the old
version back. Converted the two genuine multi-developer-coordination
steps (.mcp.json, .claude/settings.json -- whether every developer has
migrated their own machine is a fact only a human knows) from a
blocking question to a safe default (leave in place, report, offer
removal later once a developer explicitly confirms).
Left three gates as real questions, on purpose: uncommitted local
changes on CLAUDE.md (actual risk of lost work), the developer's
personal ~/.claude/CLAUDE.md (not git-tracked, carries personal
customization), and the two "should I commit this?" prompts (commit
timing is a legitimate choice, not a policy with one right answer).
Two related fixes, discovered together while debugging Wareco's duplicated
"Project" scope MCP entries:
1. New custom/setup/machine/settings.json template + a merge-safe deploy
step in sync-bcquality-knowledge.ps1 (section 10): auto-approves the
read-only/already-protocol-gated tool calls across the three
CURABIS-managed MCP servers (businesscentral's 15 static tools, al's
11 dev-loop tools, microsoft-learn's 3 docs tools) via
~/.claude/settings.json's permissions.allow -- merged into whatever
already exists, never overwritten, since that file also carries a
developer's personal settings. Tested against a real 298-entry
settings.json: preserved every existing key/array untouched, added
only the 14 genuinely-missing entries.
Found and fixed two real bugs while building this: -AsHashtable
doesn't exist in Windows PowerShell 5.1 (this script also runs via
`powershell`, not just `pwsh`) -- switched to PSCustomObject +
Add-Member. And Set-Content -Encoding utf8 writes a BOM in PS5.1 with
no utf8NoBOM option -- switched to [System.IO.File]::WriteAllText
with an explicit no-BOM UTF8Encoding, since the original file had no
BOM and a JSON parser choking on one would have silently broken every
developer's settings.json.
2. Wareco's committed .claude/settings.json still has the pre-migration
Dynamic Tool Mode tool names (bc_actions_search/describe) and an
enabledMcpjsonServers entry for al/businesscentral -- the latter is
why the MCP servers panel shows them duplicated under "Project" scope
next to the correct "User" scope registration. Added detection +
confirmed-removal migration step (mirroring the existing .mcp.json
migration's multi-developer coordination caveat) and Roemer station
16 to catch this on other pre-migration repos (gtt-marine likely has
the same file).
The 2026-08-03 follow-up's "restart Claude Code" step was falsified same
day by a full machine reboot that left Internal_CompanyNotFound unchanged.
Records the two theories ruled out with evidence (stale bridge process;
MCP config/company misconfiguration, both screenshot-verified) and states
plainly that this is a client-unfixable, likely BC/SaaS-side condition
requiring Microsoft support escalation.
Internal_CompanyNotFound recurred 2026-08-03 on two machines with the
company header already matching Navn correctly, ruling out the original
header-mismatch cause. Failure was intermittent and appeared to clear after
restarting Claude Code, suggesting a separate, still-unconfirmed session/
bridge staleness issue. Adds a follow-up section with next steps so future
sessions don't re-verify an already-correct header a third time.