[Bug] v0.4.x MCP: silent auth fails with AccountNotFound on AAD-joined Windows; interactive fallback succeeds but MCP returns 'Authentication failed' (0.2.8 works)
Nobody has claimed this yet.
- Dominant language
- PowerShell
- Stars
- 1k
- Forks
- 132
- Avg merge
- 5d 19h
- Merged PRs (30d)
- 6
Description
[Bug] v0.4.x MCP mode: silent auth fails with AccountNotFound, interactive fallback succeeds but MCP returns "Authentication failed" (0.2.8 works fine on same machine)
Summary
On an AAD-joined Windows 11 machine, workiq mcp (v0.4.1) consistently fails to acquire tokens silently, even immediately after a successful workiq ask. The interactive auth fallback transparently succeeds via Hello SSO + the device PRT (no UI shown), but the MCP server still returns {"error":"Authentication failed. Please re-authenticate by running 'workiq ask' interactively."} to JSON-RPC callers. Pinning to v0.2.8 on the same machine resolves the issue completely with zero other changes. This points to a regression introduced between 0.2.8 and 0.4.0.
Related but distinct: #120 (picker prompts every call), #116 (EULA gate + token persistence), #114 (VS Code MCP auth), #87 (identity not cached).
Environment
- WorkIQ version: 0.4.1 (works perfectly on 0.2.8)
- OS: Windows 11
- Node.js: v22 (npx)
- Device join state: AAD-joined to Microsoft tenant (
72f988bf-86f1-41af-91ab-2d7cd011db47) WamDefaultSet: YES,AzureAdPrt: YES (valid)- Client: GitHub Copilot CLI via Agency Microsoft Copilot wrapper (
agency.exe mcp workiq --transport http) - MCP child cmdline:
<.agency>\WorkIQ.Cli.win-x64\0.4.1.19742\tools\workiq.exe mcp ~/.work-iq-cli/.workiq.jsonpopulated correctly (EULA accepted, defaultAccount set, isMSITTenant true)~/.work-iq-cli/msal_token_cache.datexists, DPAPI-encrypted, contains account record but no refresh tokens
What's actually happening (from workiq -l Debug mcp stderr)
Every single invocation:
info: Microsoft.WorkIQ.Auth.ClientAppFactory[0]
Configuring authentication for Windows with broker support
dbug: Windows AppConfig: {
"ClientId": "ba081686-5d24-4bc6-a0d6-d034ecffed87",
"RedirectUri": "http://localhost",
"TenantId": "",
"IsBrokerEnabled": true,
...
}
dbug: Microsoft.WorkIQ.Auth.AccountManager[0] Found 1 cached account(s)
dbug: Microsoft.WorkIQ.Auth.AccountManager[0] Found matching account in cache
dbug: Attempting silent token acquisition with determined account (forceRefresh=False)
dbug: Silent authentication failed with MsalUiRequiredException:
Could not find a WAM account for the selected user.
Error: Status: AccountNotFound
Context: Account with id '(pii)' not found
Tag: 0x1f553780
dbug: Launching interactive authentication flow
dbug: Successfully acquired token interactively after silent failure
dbug: Token acquired successfully. Token expires at: ...
The interactive flow succeeds without showing any UI (Windows Hello SSO + device PRT). However, the MCP server still returns "Authentication failed" to the JSON-RPC caller, not a tool response with the acquired token. So the interactive fallback works but its output is discarded by MCP mode.
Why silent auth fails — WAM has no .tbacct under workiq's client_id
Decrypted MSAL cache (msal_token_cache.dat) shows a correct account record:
{
"home_account_id": "<oid>.72f988bf-86f1-41af-91ab-2d7cd011db47",
"environment": "login.windows.net",
"username": "marvinxu@microsoft.com",
"authority_type": "MSSTS",
"realm": "72f988bf-86f1-41af-91ab-2d7cd011db47",
"wam_account_ids": {
"ba081686-5d24-4bc6-a0d6-d034ecffed87": "<oid>"
}
}
…but no RefreshToken or AccessToken entries are persisted. Searching %LOCALAPPDATA%\Packages\Microsoft.AAD.BrokerPlugin_cw5n1h2txyewy\AC\TokenBroker\Accounts\*.tbacct (60 entries for marvinxu@microsoft.com from other apps like Edge/Office/Teams) for workiq's client_id ba081686-5d24-4bc6-a0d6-d034ecffed87 returns zero matches. The interactive WAM flow apparently never registers the account under workiq's client_id in the broker's TokenBroker DB, even though the MSAL cache's wam_account_ids claims it does. As a result, every subsequent silent acquisition asks WAM "find account-id X for client_id ba081686…" and gets AccountNotFound.
Steps to reproduce
- Windows 11 device, AAD-joined to Microsoft tenant
- Install:
npm install -g @microsoft/workiq@0.4.1(or use it via Agency Microsoft Copilot wrapper) workiq logout, delete~/.work-iq-cli/msal_token_cache.dat, delete~/.work-iq-cli/.workiq.jsonworkiq accept-eulaandworkiq ask(auth succeeds via WAM picker → Hello SSO completes invisibly)- Verify auth state:
~/.work-iq-cli/msal_token_cache.datis created (~3.7 KB DPAPI blob) - Run with debug:
workiq -l Debug mcpand send a JSON-RPCtools/callforask_work_iqover stdio - Observe: silent auth fails with
AccountNotFound→ interactive fallback acquires a token → MCP still returns"Authentication failed" - Repeat with
npm install @microsoft/workiq@0.2.8→ MCP works on first call
What I verified
| Test | Result |
|---|---|
Clean cache + workiq ask + try MCP |
Same AccountNotFound error |
| Remove all unrelated personal MSAs from Windows account state | No change |
Pass --account marvinxu@microsoft.com to workiq mcp |
No change (debug log shows Account identifier provided: True already) |
Set MSAL_DISABLE_BROKER=1, AZURE_IDENTITY_DISABLE_WAM=1 env vars |
Ignored — 0.4.1 hard-codes IsBrokerEnabled: true |
Full reset: no cache, no .workiq.json, fresh accept-eula + ask with explicit account selection |
No change |
| Replace 0.4.1 binary with 0.2.8 at the exact same path | ✅ MCP returns {"result":{"content":[{"type":"text","text":"Pong 👋 — I'm here and responsive..."}]}, "id":..., "jsonrpc":"2.0"} immediately |
Expected behavior
One of:
- Silent auth should succeed after
workiq askpopulates the cache (i.e. the interactive WAM flow should actually register the account in the broker DB under workiq's client_id), OR - The token successfully acquired via the interactive fallback should be returned in the MCP tool response rather than discarded with
"Authentication failed", OR - A clear error pointing at the actual root cause (e.g.
WAM broker did not register account for client_id <X>) instead of the misleading "re-authenticate by running 'workiq ask' interactively" (running it doesn't help)
Suggested investigation
- Bisect between 0.2.8 → 0.4.0 to find the commit that changed the auth path. Likely candidates: change of
ClientId, addition ofIsBrokerEnabled: true, change in WAM redirect URI, switch fromWithDefaultRedirectUri()tohttp://localhost, or change in scope set requested. - Investigate why
AcquireTokenInteractiveon AAD-joined Windows devices is not persisting the account into the WAM TokenBroker DB under workiq's client_id, but is still able to issue tokens silently via PRT. This may be specific to multi-tenant apps (TenantId: "") talking to broker on devices with an existing AAD device join. - As an immediate mitigation, the MCP layer could be taught to use the token acquired via the interactive fallback path, rather than rejecting the call with
"Authentication failed"— that string is also misleading because re-runningworkiq askdoesn't change the underlying broker DB state.
Workaround for affected users
Pin workiq to v0.2.8: npx -y @microsoft/workiq@0.2.8 mcp. Note: 0.2.8 has a smaller feature set than 0.4.x (no --account flag, no -l/--log-level global option, no get_debug_link tool) but the core ask_work_iq tool works.
Note for the Agency Microsoft Copilot team
Agency.exe currently bundles WorkIQ.Cli.win-x64 0.4.1.19742. Until this regression is resolved, downgrading agency's bundled version to 0.2.8 would unbreak agency copilot on every AAD-joined Windows machine where this manifests.
Happy to provide further debug logs, the decrypted MSAL cache, the agency-wrapped process tree, or a tcpdump if useful. The full RCA is in my repro notes.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the workiq ask and workiq mcp entry points, reproducing the behavior on Windows 11 with versions 0.4.1 and 0.2.8. Review the Debug output around AccountManager, WAM, silent acquisition, and interactive fallback, then bisect the authentication changes. Done means MCP uses the acquired token successfully or reports the actual broker failure instead of returning the misleading authentication error.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- node.js, powershell
- Domain
- authentication, cli, operating-systems
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 38/100