Problem
The current OAuth session refresh support looks close to complete, but the full flow is not functional end to end. The pieces exist, but they are not wired together in a way that makes human MCP sessions reliably refresh across normal use and server restarts.
What exists today
createSessionAuthPreHandler() contains session-aware token lookup and opportunistic refresh logic.
registerTokenRefreshService() exists and starts automatically when registered.
refreshSessionToken(sessionId) is implemented with concrete refresh + session update + notification behavior.
- Redis and memory session stores both have
tokenRefresh and token-hash mapping support.
What is missing / inconsistent
1. The plugin still wires the generic prehandler, not the session-aware one
In the main MCP plugin entrypoint, the auth path uses createAuthPreHandler(...), not createSessionAuthPreHandler(...). That means the session store and refresh metadata are not part of the normal authenticated request path.
2. session-auth-prehandler.ts is behind prehandler.ts
createSessionAuthPreHandler() does not currently match the newer behavior in createAuthPreHandler(). At minimum it appears to be missing parity for:
/mcp/.well-known skip behavior
/oauth/callback and /oauth/register skip behavior
config.excludedPaths handling
So replacing the generic handler with the session-aware one today would regress behavior.
3. The OAuth callback path does not appear to persist refresh metadata into the session
The authorization callback returns or redirects with tokens, but the session-aware refresh path depends on session.tokenRefresh already being present in the session store. Without persisting refresh metadata during callback/session establishment, later requests can link a bearer token to an MCP session but still have nothing to refresh with.
4. The background refresh service is not integrated into the main plugin path
registerTokenRefreshService() exists, but the main MCP plugin path does not appear to register it.
5. The periodic refresh loop is still a stub
performTokenRefresh() is still explicitly a placeholder. The service framework and the per-session refresh method are real, but the automatic periodic sweep over expiring sessions is not implemented.
Why this matters
For human MCP clients using OAuth authorization code flow, this creates an awkward middle state where the codebase suggests session refresh support, but in practice the end-to-end path is not dependable. In particular:
- session-aware refresh is not active by default
- refresh metadata may never be persisted
- app restarts drop in-memory session state
- the background service cannot currently rescue expiring sessions automatically
Proposed direction
Treat this as one feature that needs to be completed end to end:
- Bring
createSessionAuthPreHandler() to feature parity with createAuthPreHandler().
- Decide whether the session-aware handler should replace the generic one when OAuth session support is enabled.
- Persist
tokenRefresh and related auth/session state during the OAuth callback/session establishment flow.
- Register the token refresh service from the main plugin path when the required pieces are available.
- Implement
performTokenRefresh() so the periodic service actually refreshes expiring sessions.
- Add coverage for the full flow, including restart/persistence behavior with Redis-backed session storage.
Expected outcome
A user who authenticates via OAuth authorization code flow should be able to:
- establish an MCP session
- have refresh metadata stored with that session
- continue using the session as access tokens expire
- survive normal server restarts when using Redis-backed session storage
Right now the building blocks are present, but the feature is not complete as a system.
Problem
The current OAuth session refresh support looks close to complete, but the full flow is not functional end to end. The pieces exist, but they are not wired together in a way that makes human MCP sessions reliably refresh across normal use and server restarts.
What exists today
createSessionAuthPreHandler()contains session-aware token lookup and opportunistic refresh logic.registerTokenRefreshService()exists and starts automatically when registered.refreshSessionToken(sessionId)is implemented with concrete refresh + session update + notification behavior.tokenRefreshand token-hash mapping support.What is missing / inconsistent
1. The plugin still wires the generic prehandler, not the session-aware one
In the main MCP plugin entrypoint, the auth path uses
createAuthPreHandler(...), notcreateSessionAuthPreHandler(...). That means the session store and refresh metadata are not part of the normal authenticated request path.2.
session-auth-prehandler.tsis behindprehandler.tscreateSessionAuthPreHandler()does not currently match the newer behavior increateAuthPreHandler(). At minimum it appears to be missing parity for:/mcp/.well-knownskip behavior/oauth/callbackand/oauth/registerskip behaviorconfig.excludedPathshandlingSo replacing the generic handler with the session-aware one today would regress behavior.
3. The OAuth callback path does not appear to persist refresh metadata into the session
The authorization callback returns or redirects with tokens, but the session-aware refresh path depends on
session.tokenRefreshalready being present in the session store. Without persisting refresh metadata during callback/session establishment, later requests can link a bearer token to an MCP session but still have nothing to refresh with.4. The background refresh service is not integrated into the main plugin path
registerTokenRefreshService()exists, but the main MCP plugin path does not appear to register it.5. The periodic refresh loop is still a stub
performTokenRefresh()is still explicitly a placeholder. The service framework and the per-session refresh method are real, but the automatic periodic sweep over expiring sessions is not implemented.Why this matters
For human MCP clients using OAuth authorization code flow, this creates an awkward middle state where the codebase suggests session refresh support, but in practice the end-to-end path is not dependable. In particular:
Proposed direction
Treat this as one feature that needs to be completed end to end:
createSessionAuthPreHandler()to feature parity withcreateAuthPreHandler().tokenRefreshand related auth/session state during the OAuth callback/session establishment flow.performTokenRefresh()so the periodic service actually refreshes expiring sessions.Expected outcome
A user who authenticates via OAuth authorization code flow should be able to:
Right now the building blocks are present, but the feature is not complete as a system.