You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
In api/mcp/auth.tsrunProPreChecks, the token-validation call is the only unguarded await on the pro-gated path:
constvalidation=awaitdeps.validateProMcpToken(context.mcpTokenId);// ← no try/catch
Its sibling right below — deps.getEntitlements(...) — IS wrapped (catch → captureSilentError → fail-closed 401 "Subscription not active"). There is no top-level catch in mcpHandler or the edge entry, so a rejection at this line escapes as a raw HTTP 500 on every gated method (tools/call incl. quota-exempt describe_tool, gated resources/read, SSE replay GET), while initialize/tools/list stay healthy (PUBLIC_MCP_METHODS skip pre-checks) — and nothing reaches Sentry because captureSilentError never runs.
Why it matters
Latent today: the wired helper validateProMcpTokenOrNull (server/_shared/pro-mcp-token.ts) is internally guarded and returns {userId} | null without rejecting. But the safety lives entirely inside the helper — one refactor that lets an exception escape turns into "every tools/call 500s for OAuth users, tools/list fine, zero telemetry".
What
In
api/mcp/auth.tsrunProPreChecks, the token-validation call is the only unguarded await on the pro-gated path:Its sibling right below —
deps.getEntitlements(...)— IS wrapped (catch →captureSilentError→ fail-closed 401 "Subscription not active"). There is no top-level catch inmcpHandleror the edge entry, so a rejection at this line escapes as a raw HTTP 500 on every gated method (tools/callincl. quota-exemptdescribe_tool, gatedresources/read, SSE replay GET), whileinitialize/tools/liststay healthy (PUBLIC_MCP_METHODS skip pre-checks) — and nothing reaches Sentry becausecaptureSilentErrornever runs.Why it matters
validateProMcpTokenOrNull(server/_shared/pro-mcp-token.ts) is internally guarded and returns{userId} | nullwithout rejecting. But the safety lives entirely inside the helper — one refactor that lets an exception escape turns into "every tools/call 500s for OAuth users, tools/list fine, zero telemetry".validateProMcpTokenrejecting (there is one forgetEntitlementsthrowing).Fix
validateProMcpTokenawait in try/catch mirroring thegetEntitlementsblock:captureSilentError(err, { tags: { route: 'api/mcp', step: 'pro-token-validate' } })→ fail-closed 401 (or 503 + Retry-After, matching the transient semantics the helper already encodes).