/** * OAuth store factory using Zustand. * Creates a store with any storage adapter (file, remote, sessionStorage). */ import { createStore } from "zustand/vanilla"; import { persist, createJSONStorage } from "zustand/middleware"; import type { OAuthClientInformation, OAuthTokens, OAuthMetadata, } from "@modelcontextprotocol/sdk/shared/auth.js"; /** * OAuth state for a single server */ export interface ServerOAuthState { clientInformation?: OAuthClientInformation; preregisteredClientInformation?: OAuthClientInformation; tokens?: OAuthTokens; codeVerifier?: string; scope?: string; serverMetadata?: OAuthMetadata; } /** * Zustand store state (all servers) */ export interface OAuthStoreState { servers: Record; getServerState: (serverUrl: string) => ServerOAuthState; setServerState: (serverUrl: string, state: Partial) => void; clearServerState: (serverUrl: string) => void; } /** * Creates a Zustand store for OAuth state with the given storage adapter. * The storage adapter handles persistence (file, remote HTTP, sessionStorage, etc.). * * @param storage - Zustand storage adapter (from createJSONStorage) * @returns Zustand store instance */ export function createOAuthStore( storage: ReturnType, ) { return createStore()( persist( (set, get) => ({ servers: {}, getServerState: (serverUrl: string) => { return get().servers[serverUrl] || {}; }, setServerState: ( serverUrl: string, updates: Partial, ) => { set((state) => ({ servers: { ...state.servers, [serverUrl]: { ...state.servers[serverUrl], ...updates, }, }, })); }, clearServerState: (serverUrl: string) => { set((state) => { const rest = { ...state.servers }; delete rest[serverUrl]; return { servers: rest }; }); }, }), { name: "mcp-inspector-oauth", storage, }, ), ); }