tryaii-mcp-server
Version:
TryAII MCP Server - 15+ AI models with comparison, cost tracking, and collective intelligence
166 lines • 6.71 kB
JavaScript
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