UNPKG

msexchange-mcp

Version:

MCP server for Microsoft Exchange/Outlook email operations via Microsoft Graph API

88 lines 3.69 kB
import { SecretClient } from '@azure/keyvault-secrets'; import { DefaultAzureCredential } from '@azure/identity'; export class KeyVaultTokenCache { secretClient; cacheKeyPrefix; cacheKey; constructor(vaultUri, cacheKeyPrefix = 'mcp-tokens', userEmail) { // Use DefaultAzureCredential which works with: // - Azure CLI (local development) // - Managed Identity (when deployed) // - Environment variables const credential = new DefaultAzureCredential(); this.secretClient = new SecretClient(vaultUri, credential); this.cacheKeyPrefix = cacheKeyPrefix; // Create a unique cache key for this user // Replace dots and @ with hyphens for Key Vault naming rules const safeEmail = userEmail ? userEmail.replace(/[@.]/g, '-') : 'default'; this.cacheKey = `${cacheKeyPrefix}-${safeEmail}`; console.error(`🔐 KeyVaultTokenCache initialized for ${this.cacheKey}`); } async beforeCacheAccess(cacheContext) { try { console.error(`🔍 Retrieving token cache from Key Vault: ${this.cacheKey}`); const secret = await this.secretClient.getSecret(this.cacheKey); if (secret.value) { console.error(`✅ Found cached tokens in Key Vault`); cacheContext.tokenCache.deserialize(secret.value); } else { console.error(`📭 No cached tokens found in Key Vault`); } } catch (error) { if (error.code === 'SecretNotFound') { console.error(`📭 No cached tokens found in Key Vault (secret not found)`); // This is fine - first time use } else { console.error(`❌ Error retrieving from Key Vault:`, error.message); // Don't throw - allow MSAL to continue with empty cache } } } async afterCacheAccess(cacheContext) { if (cacheContext.cacheHasChanged) { try { const serializedCache = cacheContext.tokenCache.serialize(); console.error(`💾 Saving updated token cache to Key Vault: ${this.cacheKey}`); await this.secretClient.setSecret(this.cacheKey, serializedCache, { contentType: 'application/json', tags: { 'app': 'exchange-mcp', 'type': 'msal-token-cache', 'updated': new Date().toISOString() } }); console.error(`✅ Token cache saved to Key Vault successfully`); } catch (error) { console.error(`❌ Error saving to Key Vault:`, error.message); // Don't throw - tokens will still work for current session } } } // Helper method to clear cache for a user async clearCache() { try { console.error(`🗑️ Deleting token cache from Key Vault: ${this.cacheKey}`); const poller = await this.secretClient.beginDeleteSecret(this.cacheKey); await poller.pollUntilDone(); console.error(`✅ Token cache deleted from Key Vault`); } catch (error) { console.error(`❌ Error deleting from Key Vault:`, error.message); } } // Helper method to check if cache exists async hasCache() { try { await this.secretClient.getSecret(this.cacheKey); return true; } catch (error) { return false; } } } //# sourceMappingURL=keyVaultTokenCache.js.map