UNPKG

@the_cfdude/productboard-mcp

Version:

Model Context Protocol server for Productboard REST API with dynamic tool loading

107 lines (106 loc) 3.67 kB
/** * Session-aware configuration loading for ProductBoard MCP Server * Provides isolated configuration per session to prevent conflicts */ import { debugLog } from './debug-logger.js'; /** * Load configuration for a specific session */ export function loadSessionConfig(session) { const cacheKey = 'session-config'; // Check session cache first if (session.configCache.has(cacheKey)) { debugLog('session-config', 'Configuration loaded from session cache', { sessionId: session.sessionId, }); return session.configCache.get(cacheKey); } // Load configuration from environment variables const config = { apiToken: process.env.PRODUCTBOARD_API_TOKEN, baseUrl: process.env.PRODUCTBOARD_BASE_URL || 'https://api.productboard.com', timeouts: { request: parseInt(process.env.PRODUCTBOARD_REQUEST_TIMEOUT || '30000'), response: parseInt(process.env.PRODUCTBOARD_RESPONSE_TIMEOUT || '30000'), }, rateLimiting: { enabled: process.env.PRODUCTBOARD_RATE_LIMITING !== 'false', maxRequestsPerMinute: parseInt(process.env.PRODUCTBOARD_MAX_REQUESTS_PER_MINUTE || '100'), }, caching: { enabled: process.env.PRODUCTBOARD_CACHING !== 'false', ttlSeconds: parseInt(process.env.PRODUCTBOARD_CACHE_TTL || '300'), }, }; // Cache the configuration in the session session.configCache.set(cacheKey, config); debugLog('session-config', 'Configuration loaded and cached', { sessionId: session.sessionId, hasApiToken: !!config.apiToken, baseUrl: config.baseUrl, rateLimitingEnabled: config.rateLimiting?.enabled, cachingEnabled: config.caching?.enabled, }); return config; } /** * Update session configuration */ export function updateSessionConfig(session, updates) { const cacheKey = 'session-config'; const currentConfig = session.configCache.get(cacheKey) || {}; const updatedConfig = { ...currentConfig, ...updates, }; session.configCache.set(cacheKey, updatedConfig); debugLog('session-config', 'Session configuration updated', { sessionId: session.sessionId, updates: Object.keys(updates), }); } /** * Clear session configuration cache */ export function clearSessionConfigCache(session) { const cacheKey = 'session-config'; session.configCache.delete(cacheKey); debugLog('session-config', 'Session configuration cache cleared', { sessionId: session.sessionId, }); } /** * Validate session configuration */ export function validateSessionConfig(config) { const errors = []; if (!config.apiToken) { errors.push('PRODUCTBOARD_API_TOKEN environment variable is required'); } if (!config.baseUrl) { errors.push('Base URL is required'); } else { try { new URL(config.baseUrl); } catch { errors.push('Base URL must be a valid URL'); } } if (config.timeouts?.request && (config.timeouts.request < 1000 || config.timeouts.request > 120000)) { errors.push('Request timeout must be between 1000ms and 120000ms'); } if (config.rateLimiting?.maxRequestsPerMinute && config.rateLimiting.maxRequestsPerMinute < 1) { errors.push('Rate limiting max requests per minute must be at least 1'); } if (config.caching?.ttlSeconds && config.caching.ttlSeconds < 0) { errors.push('Cache TTL seconds cannot be negative'); } return { valid: errors.length === 0, errors, }; }