UNPKG

tryaii-mcp-server

Version:

TryAII MCP Server - 15+ AI models with comparison, cost tracking, and collective intelligence

166 lines 6.71 kB
import { logger } from '../utils/logger.js'; import { config } from '../utils/config.js'; export class ApiKeyService { constructor() { logger.info('ApiKeyService initialized', { userKeysConfigured: Object.keys(config.apiKeys.user), tryaiiKeysAvailable: Object.keys(config.apiKeys.tryaii), totalProvidersSupported: ['openai', 'anthropic', 'google', 'deepseek', 'xai', 'mistral', 'brave'].length }); } /** * 🔑 Smart API Key Resolution * Priority: User keys (free) > TryAII keys (paid) * Returns configuration for MCP process and billing info */ resolveApiKeys(userProvidedKeys = {}) { const resolved = {}; const fallbackUsed = []; let useUserBalance = false; const providers = ['openai', 'anthropic', 'google', 'deepseek', 'xai', 'mistral', 'brave']; for (const provider of providers) { // 1st Priority: Runtime user-provided keys (passed to function) const runtimeUserKey = userProvidedKeys[provider]; // 2nd Priority: Configuration user keys (from user-keys.env) const configUserKey = config.apiKeys.user[provider]; // 3rd Priority: TryAII fallback keys (from tryaii-keys.env) const tryaiiKey = config.apiKeys.tryaii[provider]; if (runtimeUserKey && this.isValidApiKey(runtimeUserKey, provider)) { // Runtime user key - highest priority, free usage resolved[provider] = runtimeUserKey; logger.debug(`Using runtime user-provided ${provider} key`); } else if (configUserKey && this.isValidApiKey(configUserKey, provider)) { // Configuration user key - second priority, free usage resolved[provider] = configUserKey; logger.debug(`Using config user ${provider} key`); } else if (tryaiiKey && this.isValidApiKey(tryaiiKey, provider)) { // TryAII fallback key - lowest priority, paid usage resolved[provider] = tryaiiKey; fallbackUsed.push(provider); useUserBalance = true; logger.debug(`Using TryAII fallback ${provider} key`); } else { // No valid key available logger.warn(`No valid API key available for ${provider}`, { hasRuntimeKey: !!runtimeUserKey, hasConfigKey: !!configUserKey, hasTryaiiKey: !!tryaiiKey }); } } const userProvidedCount = Object.keys(resolved).length - fallbackUsed.length; const summary = this.generateKeySummary(userProvidedCount, fallbackUsed.length, fallbackUsed); logger.info('API keys resolved', { totalProviders: providers.length, resolvedProviders: Object.keys(resolved).length, userProvidedCount, fallbackCount: fallbackUsed.length, fallbackProviders: fallbackUsed, willChargeUserBalance: useUserBalance, summary }); return { keys: resolved, useUserBalance, fallbackUsed, summary }; } /** * Generates human-readable summary of key resolution */ generateKeySummary(userCount, fallbackCount, fallbackProviders) { if (userCount > 0 && fallbackCount === 0) { return `✅ Using ${userCount} user key(s) - FREE usage`; } else if (userCount === 0 && fallbackCount > 0) { return `💰 Using ${fallbackCount} TryAII key(s) (${fallbackProviders.join(', ')}) - PAID usage`; } else if (userCount > 0 && fallbackCount > 0) { return `🔄 Mixed: ${userCount} user key(s) (free) + ${fallbackCount} TryAII key(s) (paid: ${fallbackProviders.join(', ')})`; } else { return `❌ No API keys available`; } } /** * Validates API key format for specific provider */ isValidApiKey(key, provider) { if (!key || key.includes('your_') || key.includes('your-') || key.includes('_here')) { return false; } // Basic format validation switch (provider) { case 'openai': return key.startsWith('sk-') || key.startsWith('sk-proj-'); case 'anthropic': return key.startsWith('sk-ant-'); case 'google': return key.length > 10; // Google keys vary in format case 'deepseek': return key.startsWith('sk-') || key.length > 10; case 'xai': return key.startsWith('xai-') || key.length > 10; case 'mistral': return key.length > 10; // Mistral keys vary in format case 'brave': return key.length > 10; // Brave search keys default: return key.length > 5; } } /** * Gets environment variables for MCP process */ getEnvironmentForMCP(apiKeys) { const env = {}; if (apiKeys.openai) env.OPENAI_API_KEY = apiKeys.openai; if (apiKeys.anthropic) env.ANTHROPIC_API_KEY = apiKeys.anthropic; if (apiKeys.google) env.GOOGLE_API_KEY = apiKeys.google; if (apiKeys.deepseek) env.DEEPSEEK_API_KEY = apiKeys.deepseek; if (apiKeys.xai) env.XAI_API_KEY = apiKeys.xai; if (apiKeys.mistral) env.MISTRAL_API_KEY = apiKeys.mistral; if (apiKeys.brave) env.BRAVE_API_KEY = apiKeys.brave; return env; } /** * Gets configuration summary for debugging */ getConfigurationStatus() { const userKeys = Object.keys(config.apiKeys.user); const tryaiiKeys = Object.keys(config.apiKeys.tryaii); const allProviders = ['openai', 'anthropic', 'google', 'deepseek', 'xai', 'mistral', 'brave']; const coveredProviders = new Set([...userKeys, ...tryaiiKeys]); const coverage = `${coveredProviders.size}/${allProviders.length} providers covered`; return { userKeys, tryaiiKeys, totalAvailable: coveredProviders.size, coverage }; } /** * Gets count of available providers */ getAvailableProvidersCount(apiKeys) { return Object.keys(apiKeys).length; } /** * Gets list of available providers */ getAvailableProviders(apiKeys) { return Object.keys(apiKeys); } } //# sourceMappingURL=ApiKeyService.js.map