UNPKG

@simonecoelhosfo/optimizely-mcp-server

Version:

Optimizely MCP Server for AI assistants with integrated CLI tools

233 lines 8.41 kB
/** * Pagination Configuration Manager * @description Centralized configuration for pagination behavior across the MCP server. * Manages page sizes, bypass limits, and entity-specific defaults to ensure * consistent pagination behavior and prevent overwhelming AI agents with large datasets. * * Key features: * - Environment-based configuration with sensible defaults * - Entity-specific pagination rules based on typical dataset sizes * - Smart bypass detection for small entities (attributes, environments) * - Hard limits to prevent memory issues with large datasets * * @author Optimizely MCP Server * @version 1.0.0 */ /** * Manages pagination configuration for the MCP server */ export class PaginationConfigManager { config; entityDefaults; constructor() { // Load configuration from environment variables with defaults this.config = { defaultPageSize: parseInt(process.env.PAGINATION_DEFAULT_PAGE_SIZE || '25'), complexPageSize: parseInt(process.env.PAGINATION_COMPLEX_PAGE_SIZE || '25'), simplePageSize: parseInt(process.env.PAGINATION_SIMPLE_PAGE_SIZE || '25'), bypassMax: parseInt(process.env.PAGINATION_BYPASS_MAX || '200'), autoBypassEntities: (process.env.PAGINATION_AUTO_BYPASS_ENTITIES || 'attribute,environment,collaborator').split(',').map(e => e.trim()), warnThreshold: parseInt(process.env.PAGINATION_WARN_THRESHOLD || '100') }; // Define entity-specific defaults based on typical dataset sizes this.entityDefaults = { // Small datasets - bypass pagination by default attribute: { autoBypass: true, typicalSize: '10-50', warnThreshold: 50 }, environment: { autoBypass: true, typicalSize: '2-4', warnThreshold: 10 }, collaborator: { autoBypass: true, typicalSize: '5-20', warnThreshold: 30 }, list_attribute: { autoBypass: true, typicalSize: '5-20', warnThreshold: 30 }, webhook: { autoBypass: true, typicalSize: '5-15', warnThreshold: 20 }, // Medium datasets - paginate by default audience: { autoBypass: false, typicalSize: '20-100', warnThreshold: 50 }, event: { autoBypass: false, typicalSize: '50-200', warnThreshold: 100 }, extension: { autoBypass: false, typicalSize: '10-50', warnThreshold: 30 }, group: { autoBypass: false, typicalSize: '10-50', warnThreshold: 30 }, // Large datasets - always paginate flag: { autoBypass: false, typicalSize: '100-1000', warnThreshold: 500 }, experiment: { autoBypass: false, typicalSize: '50-500', warnThreshold: 200 }, page: { autoBypass: false, typicalSize: '50-500', warnThreshold: 200 }, campaign: { autoBypass: false, typicalSize: '20-200', warnThreshold: 100 }, variation: { autoBypass: false, typicalSize: '100-1000', warnThreshold: 300 }, rule: { autoBypass: false, typicalSize: '100-1000', warnThreshold: 300 }, // Analytics - special handling analytics: { autoBypass: false, typicalSize: '25-10000', warnThreshold: 1000 }, ruleset: { autoBypass: false, typicalSize: '100-1000', warnThreshold: 300 } }; } /** * Get the appropriate page size for an entity type * @param entityType The type of entity being queried * @param isSimplified Whether simplified/condensed data is requested * @returns The page size to use */ getPageSize(entityType, isSimplified = false) { if (isSimplified) { return this.config.simplePageSize; } // For complex entities with nested data, use smaller page size const complexEntities = ['flag', 'experiment', 'campaign', 'ruleset']; if (complexEntities.includes(entityType)) { return this.config.complexPageSize; } // Analytics gets default page size from env or 10 if (entityType === 'analytics') { return parseInt(process.env.ANALYTICS_DEFAULT_PAGE_SIZE || '25'); } return this.config.defaultPageSize; } /** * Check if pagination should be automatically bypassed for an entity type * @param entityType The type of entity being queried * @returns Whether to bypass pagination */ shouldAutoBypass(entityType) { // Check entity-specific defaults first const entityDefault = this.entityDefaults[entityType]; if (entityDefault !== undefined) { return entityDefault.autoBypass; } // Fall back to environment configuration return this.config.autoBypassEntities.includes(entityType); } /** * Get the maximum number of records allowed when bypassing pagination * @returns The bypass limit */ getBypassLimit() { return this.config.bypassMax; } /** * Get the warning threshold for an entity type * @param entityType The type of entity * @returns The number of records that triggers a warning */ getWarnThreshold(entityType) { const entityDefault = this.entityDefaults[entityType]; if (entityDefault?.warnThreshold !== undefined) { return entityDefault.warnThreshold; } return this.config.warnThreshold; } /** * Check if a bypass request is valid * @param totalCount The total number of records * @param requestedBypass Whether bypass was explicitly requested * @returns Object indicating if bypass is allowed and any warnings */ validateBypassRequest(totalCount, requestedBypass) { if (!requestedBypass) { return { allowed: false }; } if (totalCount > this.config.bypassMax) { return { allowed: false, reason: `Cannot bypass pagination for ${totalCount} records (max: ${this.config.bypassMax})`, suggestion: 'Use export functionality or paginate through results' }; } if (totalCount > this.config.warnThreshold) { return { allowed: true, reason: `Large dataset (${totalCount} records) - consider using export for better performance` }; } return { allowed: true }; } /** * Get entity metadata for documentation * @param entityType The type of entity * @returns Metadata about the entity's pagination behavior */ getEntityMetadata(entityType) { const defaults = this.entityDefaults[entityType] || { autoBypass: false, typicalSize: 'varies', warnThreshold: this.config.warnThreshold }; return { autoBypass: this.shouldAutoBypass(entityType), typicalSize: defaults.typicalSize, recommendation: defaults.autoBypass ? 'Small dataset - pagination bypassed by default' : 'Large dataset - pagination recommended' }; } /** * Get all configuration values for debugging * @returns Current configuration */ getConfig() { return { ...this.config }; } } // Export singleton instance for consistent configuration export const paginationConfig = new PaginationConfigManager(); //# sourceMappingURL=PaginationConfig.js.map