@the_cfdude/productboard-mcp
Version:
Model Context Protocol server for Productboard REST API with dynamic tool loading
107 lines (106 loc) • 3.67 kB
JavaScript
/**
* 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,
};
}