New features
Optimize Session Store DB Operations
Reduces redundant database round-trips across the OAuth connection lifecycle by 40β87%, depending on auth type and scenario. Eleven areas of waste were identified and eliminated:Single-table session + credentials
mcp_credentials table eliminated. All credential fields (client_information, tokens, code_verifier, client_id, oauth_state) live as nullable columns on mcp_sessions. get({ includeCredentials: true }) is a plain SELECT * with no JOIN. getCredentials(), patchCredentials(), clearAll(), and delete() are all single-operation queries. SessionResult = Session β credential fields accessed directly (session.clientId).
Cost eliminated per deployment: 1 table, 1 UUID PK + sequence, 1 UNIQUE constraint, 1 FK constraint, 1 trigger, 1 index, and (Supabase) 4 RLS policies.
Challenge-based code verifier (in-memory only)
PKCE code verifier stored in-memory (_cachedCodeVerifier) β no DB write on saveCodeVerifier(). redirectToAuthorization() compares SHA-256 challenge in-memory, persists raw verifier to DB only on match for cross-instance callback. codeVerifier() reads in-memory β ALS context β DB fallback (3-tier lookup). codeVerifierChallenge and codeVerifierNonce removed from all backends, types, and migrations β no DB columns, no persistence overhead.
authUrl in-memory only
redirectToAuthorization() stores _authUrl in-memory β does NOT persist to DB (was waste on every OAuth start, never read back).
PKCE dead-write elimination
Removed allpatchCredentials() calls referencing codeVerifierChallenge and codeVerifierNonce from StorageOAuthClientProvider. DB columns code_verifier_challenge and code_verifier_nonce removed from all migrations and backends.
Internal provider overhead eliminated
_hasCodeVerifierflag β firstsaveCodeVerifier()sets in-memory flag; subsequent calls return immediately (0 ops)- Cached tokens β
tokens()returns_cachedTokensfrom constructor (0R);saveTokens()updates both DB and cache hasSessionflag βMCPOAuthClientOptions.hasSession: trueskipssessions.get()existence check when caller already loaded the session- Combined fetch β
get({ includeCredentials: true })returns credential fields on theSessionobject directly, eliminating separategetCredentials()call
Remove redundant checkState() in finishAuth()
Before: called checkState() (1β2R), then consumeState() which called checkState() again (1β2R). After: calls consumeState() only β it validates internally. Saves 1β2R per finishAuth().
Unified observability
SinglesendEvent callback for RPC timing, DB read/write, and client lifecycle events. withDbObservability auto-wraps session store β all DB read/write timing flows through sendEvent. handleRequest() emits rpc:start/rpc:end with method, sessionId, and duration. Consumer gets one stream of McpObservabilityEvents covering RPC timing, DB operations, and client lifecycle β one callback, no manual wiring.
SSE handler refactor
SSEConnectionManager cleaned up with 5 extracted private helpers (restoreClient, cacheClient, attachClientEvents, requireSession, connectAndDiscover, findExistingSession), 2 event factories, JSDoc on all 14 RPC methods, structured sections, and rpc:start/rpc:end timing observability in the unified dispatch() wrapper.
Tool policy management
ToolPolicyGateway accepts a ToolClient implementing getServerUrl, checkToolAllowed, listAllowedTools, and addAllowedTool for per-session tool allowlists with optional SQL storage.
OAuth popup reconnect
SSEClient gained a reconnect method for transport re-establishment without a fresh OAuth handshake. React ConnectionItem and ConnectionList components expose reconnect controls with streamlined error handling.
allTools in tools_discovered
Thetools_discovered event now includes an allTools payload for management UIs. MCPClient implements in-memory caching for tool fetches.
Client credentials flow
MCPClient accepts clientId and clientSecret as connection parameters for OAuth client credentials grant flows.
Session enable/disable
updateSession() toggles enabled on a session. Disabled sessions are excluded from AI tools via MultiSessionClient.fetchActiveSessions() (s.enabled !== false), blocked at SSEConnectionManager.getOrCreateClient() with βSession is disabledβ, and exposed in listSessions() for UI toggle state. Re-enabling requires no re-authentication. React useMcp hook exposes updateSession(sessionId, enabled).
ServerInfo capture
MCPClient captures serverInfo from this.client.getServerVersion() after connect(). getServerInfo() returns the full Implementation object (name, version, title, icons). getServerName() uses title ?? name ?? config.serverName. mcp-server analytics pipeline passes serverIcons through recordToolCallEvent(), stored as server_icons JSONB in mcp_tool_call_events.
Performance
First-time connection DB round-trips:| Auth type | Before | After | Savings |
|---|---|---|---|
| No Auth | 3R 2W | 1R 2W | β2R (66%) |
| Client Credentials | 3R 4W | 1R 3W | β2R (66%) |
| OAuth | 9R 10W | 5R 8W | β4R (44%) |
| Auth type | Before | After | Savings |
|---|---|---|---|
| No Auth | 4R 1W | 1R 1W | β3R (75%) |
| Client Credentials | 4R 1W | 1R 1W | β3R (75%) |
| OAuth (valid tokens) | 8R 2W | 1R 1W | β7R (87%) |
| OAuth (expired tokens) | 8R 2W | ~3R 2W | β5R (62%) |
Updates
- MCPClient refactored β Configuration consolidated into a single options object.
ensureSessionreplacesinitializefor session management. - Monorepo restructured β SDK moved to
packages/sdk/with npm workspaces.release.ymlpaths updated.AGENTS.mdadded at repo root.
Bug fixes
- Stale client pruning β
MultiSessionClientprunes staleMCPClientinstances to prevent OAuth refresh issues after session expiry (PR #167) - Session expiry recovery β
MCPClientrecovers fromMCP_SESSION_EXPIREDusingwithRetry, nulling the OAuth client to trigger a clean reconnect (PR #170) - Disconnect logic β Streamlined disconnect handling in
MCPClientandMultiSessionClientto prevent orphaned connections during session teardown

