* 🔌 fix: Resolve MCP OAuth flow state race condition
The OAuth callback arrives before the flow state is stored because
`createFlow()` returns a long-running Promise that only resolves on
flow COMPLETION, not when the initial PENDING state is persisted.
Calling it fire-and-forget with `.catch(() => {})` meant the redirect
happened before the state existed, causing "Flow state not found"
errors.
Changes:
- Add `initFlow()` to FlowStateManager that stores PENDING state and
returns immediately, decoupling state persistence from monitoring
- Await `initFlow()` before emitting the OAuth redirect so the
callback always finds existing state
- Keep `createFlow()` in the background for monitoring, but log
warnings instead of silently swallowing errors
- Increase FLOWS cache TTL from 3 minutes to 10 minutes to give
users more time to complete OAuth consent screens
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* 🔌 refactor: Revert FLOWS cache TTL change
The race condition fix (initFlow) is sufficient on its own.
TTL configurability should be a separate enhancement via
librechat.yaml mcpSettings rather than a hardcoded increase.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* 🔌 fix: Address PR review — restore FLOWS TTL, fix blocking-path race, clean up dead args
- Restore FLOWS cache TTL to 10 minutes (was silently dropped back to 3)
- Add initFlow before oauthStart in blocking handleOAuthRequired path
to guarantee state persistence before any redirect
- Pass {} to createFlow metadata arg (dead after initFlow writes state)
- Downgrade background monitor .catch from logger.warn to logger.debug
- Replace process.nextTick with Promise.resolve in test (correct semantics)
- Add initFlow TTL assertion test
- Add blocking-path ordering test (initFlow → oauthStart → createFlow)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix: create new flows on invalid_grant errors
* chore: fix failing test
* chore: keep isOAuthError test function in sync with implementation
* test: add tests for OAuth error detection on invalid grant errors
* test: add tests for creating new flows when token expires
* test: add test for flow clean up prior to creation
* refactor: consolidate token expiration handling in FlowStateManager
- Removed the old token expiration checks and replaced them with a new method, `isTokenExpired`, to streamline the logic.
- Introduced `normalizeExpirationTimestamp` to handle timestamp normalization for both seconds and milliseconds.
- Updated tests to ensure proper functionality of flow management with token expiration scenarios.
* fix: conditionally setup cleanup handlers in FlowStateManager
- Updated the FlowStateManager constructor to only call setupCleanupHandlers if the ci parameter is not set, improving flexibility in flow management.
* chore: enhance OAuth token refresh logging
- Introduced a new method, `processRefreshResponse`, to streamline the processing of token refresh responses from the OAuth server.
- Improved logging to provide detailed information about token refresh operations, including whether new tokens were received and if the refresh token was rotated.
- Updated existing token handling logic to utilize the new method, ensuring consistency and clarity in token management.
* chore: enhance logging for MCP server reinitialization
- Updated the logging in the reinitMCPServer function to provide more detailed information about the response, including success status, OAuth requirements, presence of the OAuth URL, and the count of tools involved. This improves the clarity and usefulness of logs for debugging purposes.
---------
Co-authored-by: Danny Avila <danny@librechat.ai>