Skip to content

Repair session info on demand + fix callTool token reconcile - #184

Open
rohitthughtspot wants to merge 2 commits into
mainfrom
fix/sessioninfo-lazy-repair-184
Open

Repair session info on demand + fix callTool token reconcile#184
rohitthughtspot wants to merge 2 commits into
mainfrom
fix/sessioninfo-lazy-repair-184

Conversation

@rohitthughtspot

@rohitthughtspot rohitthughtspot commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

Problem

After a cold-start reconnect (~24h, once the frozen props access token has expired), list_orgs/switch_org disappear and datasource-discovery gating breaks — even though the keep-warm token is valid.

Cause

sessionInfo is fetched once at init via getSessionInfo(), which runs before postInit reconciles the keep-warm global token from the DO. On that reconnect the fetch authenticates with the dead frozen props token, fails, and leaves sessionInfo null for the instance lifetime. Org-tool visibility and datasource gating read sessionInfo, so they mis-gate — while the DO still holds a valid token (data tool calls, which reconcile it at call time, keep working).

Fix

  • ensureSessionInfo() — refetch session info when it's null, called at the top of listTools()/callTool(). By then postInit has loaded the kept-warm token, so the refetch authenticates with it. No-op (no network call) once populated — happy path unaffected.
  • callTool per-call reconcile keyed on !this.activeOrgToken — so a data call always gets a freshly reconciled global token when no org token drives it (covers non-orgs clusters and the no-active-org case).

Test

Regression test reproduces the failure (init getSessionInfo fails on an expired props token; DO holds a valid token) and asserts the repair restores sessionInfo and the org tools. Verified it fails without the fix. Server suites pass.

🤖 Generated with Claude Code

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a lazy session info repair mechanism (ensureSessionInfo) to handle cases where the initial, init-time getSessionInfo call fails due to an expired token. This ensures that subsequent tool list and call requests can repair the session info using the kept-warm token. Feedback on these changes highlights two key issues: first, when sessionInfo is repaired on-demand, the active org initialization logic does not run, leaving the session unscoped to the user's default active org; second, concurrent calls to ensureSessionInfo can cause race conditions and duplicate trackers, which should be guarded against using a promise.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread src/servers/mcp-server.ts Outdated
Comment on lines +439 to +441
// Repair session info if the init-time fetch failed, so the org-tools gate
// below (and getActiveToken's token selection) act on the real state.
await this.ensureSessionInfo();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

If the init-time getSessionInfo fails (e.g., due to an expired token), postInit() skips defaulting this.activeOrgId to this.sessionInfo.currentOrgId. When ensureSessionInfo() later repairs this.sessionInfo during a tool call, this.activeOrgId remains undefined because the default active org initialization logic only ran in postInit(). This means the session will continue to run without being scoped to the user's default active org (no x-thoughtspot-orgs header or org-scoped token), which can lead to data discrepancies or errors. We should run the active org initialization logic inline when sessionInfo is repaired.

		// Repair session info if the init-time fetch failed, so the org-tools gate
		// below (and getActiveToken's token selection) act on the real state.
		const hadSessionInfo = !!this.sessionInfo;
		await this.ensureSessionInfo();
		if (!hadSessionInfo && this.sessionInfo && this.areOrgToolsAvailable()) {
			await this.loadActiveOrg();
			if (!this.activeOrgId) {
				const currentOrgId =
					this.sessionInfo.currentOrgId != null
						? String(this.sessionInfo.currentOrgId)
						: undefined;
				if (currentOrgId) {
					this.activeOrgId = currentOrgId;
				}
			}
			if (this.activeOrgId && !this.activeOrgToken) {
				try {
					await this.forceRecreateActiveOrgToken(recorder);
				} catch (error) {
					console.error("Failed to mint active org token after repair:", error);
				}
			}
		}

Comment thread src/servers/mcp-server-base.ts
@rohitthughtspot
rohitthughtspot force-pushed the fix/sessioninfo-lazy-repair-184 branch from dd7b41e to a66d443 Compare July 12, 2026 21:36
@mouryabalabhadra

Copy link
Copy Markdown
Collaborator

@copilot review pr

Copilot AI commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

@copilot review pr

Reviewed the PR changes and I don’t see any high-signal bugs or security issues to address right now. CI is currently green on the latest pull_request run; earlier failures on this branch were from a transient Coveralls 504 error.

Copilot AI requested a review from mouryabalabhadra July 13, 2026 15:57
@rohitthughtspot
rohitthughtspot force-pushed the fix/sessioninfo-lazy-repair-184 branch from 9979b41 to 72b2681 Compare July 14, 2026 13:12
… getSessionInfo

sessionInfo is fetched once at init via getSessionInfo(). Previously that ran
before the keep-warm global token was reconciled from the token-store DO, so
on a cold-start reconnect after the frozen props access token expired (~24h),
getSessionInfo authenticated with the dead token, failed, and left sessionInfo
null for the DO's lifetime — silently hiding list_orgs/switch_org and
mis-gating datasource discovery, even though the DO held a valid kept-warm
token (data tool calls, which reconcile the DO token at call time, kept
working).

- Reorder (primary fix): add a preInit() hook that runs before
  initializeService(), and move MCPServer's global-token reconcile there (out
  of postInit's top). getSessionInfo now authenticates with the kept-warm DO
  token on the first try, so sessionInfo is populated correctly at init.
- ensureSessionInfo() safety net in listTools: if init's getSessionInfo still
  failed (e.g. a transient error) and sessionInfo is null, refetch on demand so
  the advertised org-tool list reflects the real cluster state. No-op once
  populated; guarded by an in-flight promise so concurrent list calls share one
  fetch (no duplicate getSessionInfo or MixpanelTracker).
- isOrgsEnabled() defaults to true when sessionInfo is absent, so org tools stay
  visible in the narrow window before the refetch completes.
- callTool: reconcile the global token per call keyed on the absence of an
  active org token, so a data call always gets a fresh global token when no org
  token drives it.
- Extract postInit's active-org bootstrap into ensureActiveOrg().
- Drop the [DEBUG] console.warn in isDatasourceDiscoveryAvailable (log noise).

Tests: init succeeds via the warm token (reorder), the concurrency guard
coalesces concurrent refetches, and existing suites pass (635).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@rohitthughtspot
rohitthughtspot force-pushed the fix/sessioninfo-lazy-repair-184 branch from 72b2681 to 491b6bf Compare July 14, 2026 13:19
…repair-184

# Conflicts:
#	src/servers/mcp-server-base.ts
#	test/servers/mcp-server-base.spec.ts
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants