@simonecoelhosfo/optimizely-mcp-server
Version:
Optimizely MCP Server for AI assistants with integrated CLI tools
388 lines • 14.7 kB
TypeScript
/**
* Entity Router for Parametric Tool Architecture
* @description Central routing system for entity operations across Optimizely platforms.
* Enables scaling from entity-specific tools to parametric tools that can handle
* any entity type through a unified interface.
*
* This router is the foundation of the parametric architecture that allows us to:
* - Scale from 11 tools to ~20 tools while covering 36+ API endpoints
* - Maintain consistent operation patterns across all entity types
* - Support both Web Experimentation and Feature Experimentation platforms
* - Enable future entity types without creating new tools
*/
import { OptimizelyAPIHelper } from '../api/OptimizelyAPIHelper.js';
import { CacheManager } from '../cache/CacheManager.js';
import { SQLiteEngine } from '../storage/SQLiteEngine.js';
/**
* Supported entity types across both Optimizely platforms
*/
export type EntityType = 'project' | 'flag' | 'experiment' | 'audience' | 'attribute' | 'list_attribute' | 'event' | 'campaign' | 'environment' | 'feature' | 'feature_variable' | 'ruleset' | 'rule' | 'variation' | 'variable_definition' | 'page' | 'extension' | 'group' | 'segment' | 'webhook' | 'collaborator' | 'report' | 'result' | 'recommendation';
/**
* Platform detection for entity operations
*/
export type Platform = 'feature' | 'web' | 'auto';
/**
* Project type information from API
*/
export interface ProjectTypeInfo {
projectId: string;
projectType: Platform;
projectName?: string;
isValid: boolean;
lastChecked: number;
}
/**
* Supported CRUD operations
*/
export type EntityOperation = 'list' | 'get' | 'create' | 'update' | 'delete' | 'archive' | 'enable' | 'disable' | 'history' | 'brainstorm' | 'upload' | 'bulk_update' | 'bulk_archive' | 'get_results';
/**
* Entity operation parameters
*/
export interface EntityOperationParams {
operation: EntityOperation;
entityType: EntityType;
platform?: Platform;
projectId?: string;
entityId?: string;
entityKey?: string;
filters?: Record<string, any>;
data?: Record<string, any>;
options?: Record<string, any>;
}
/**
* Entity metadata for routing decisions
*/
interface EntityMetadata {
platform: Platform;
apiEndpoint: string;
supportsArchive: boolean;
supportsPagination: boolean;
paginationType: 'page' | 'cursor';
identifierField: 'id' | 'key' | 'both';
parentEntity?: EntityType;
}
/**
* EntityRouter Class
* @description Routes entity operations to appropriate handlers based on entity type
* and platform. Provides a unified interface for all entity operations while handling
* the complexity of different API patterns and requirements.
*/
export declare class EntityRouter {
private apiHelper;
private cacheManager;
private storage;
private defaultsManager;
private schemaBuilder;
private mcpTools?;
/**
* Project type cache to avoid repeated API calls
* Maps project ID to project type information
*/
private projectTypeCache;
/**
* Cache TTL in milliseconds (30 minutes)
*/
private readonly CACHE_TTL;
/**
* Entity metadata registry for routing decisions
*/
private entityMetadata;
constructor(apiHelper: OptimizelyAPIHelper, cacheManager: CacheManager, storage: SQLiteEngine);
/**
* Get or create OptimizelyMCPTools instance
* @returns OptimizelyMCPTools instance
*/
private getMCPTools;
/**
* Updates local cache with entity data after successful API operations
* @param entityType - Type of entity that was updated
* @param apiResult - Result from API operation
* @param projectId - Project ID for the entity
* @param identifier - Entity identifier (fallback if API result doesn't contain ID)
*/
private updateCacheAfterOperation;
/**
* Routes an entity operation to the appropriate handler
* @param params - Entity operation parameters
* @returns Promise resolving to operation result
*/
routeEntityOperation(params: EntityOperationParams): Promise<any>;
/**
* Handles list operations for any entity type with cache-first approach
* @returns Object with data array and pagination metadata
*/
private handleListOperation;
/**
* Query entities from local cache database with pagination support
* @returns Object with data array and pagination metadata
*/
private queryFromCache;
/**
* Query entities from API (fallback method) with pagination support
* @returns Object with data array and pagination metadata
*/
private queryFromAPI;
/**
* Build standardized paginated response from API response
* Handles different API response formats (array vs object with metadata)
*/
private buildPaginatedResponse;
/**
* Get database table name for entity type
*/
private getTableName;
/**
* Get valid database columns for an entity type
* Based on actual database schema inspection
*/
private getValidColumnsForEntity;
/**
* Build WHERE clause for database queries
*/
private buildWhereClause;
/**
* Deserialize entity from SQLite storage format back to API format
* Handles boolean conversion (0/1 -> false/true) and JSON parsing
*/
private deserializeEntityFromStorage;
/**
* Handles get operations for any entity type
*/
handleGetOperation(entityType: EntityType, projectId?: string, identifier?: string, options?: Record<string, any>): Promise<any>;
/**
* Handles create operations for any entity type
*/
handleCreateOperation(entityType: EntityType, projectId?: string, data?: Record<string, any>, options?: Record<string, any>): Promise<any>;
/**
* Handles update operations for any entity type
*/
handleUpdateOperation(entityType: EntityType, projectId?: string, identifier?: string, data?: Record<string, any>, options?: Record<string, any>): Promise<any>;
/**
* Handles delete operations for any entity type
*/
private handleDeleteOperation;
/**
* Handles archive operations for any entity type
*/
private handleArchiveOperation;
/**
* Gets metadata for an entity type
*/
getEntityMetadata(entityType: EntityType): EntityMetadata | undefined;
/**
* Searches for entities by ID or key only
* @param params - Search parameters including entity type, project ID, and search criteria
* @returns Array of matching entities
*/
searchEntities(params: {
entityType: EntityType;
projectId?: string;
searchCriteria: {
id?: string;
key?: string;
name?: string;
flag_key?: string;
environment_key?: string;
};
options?: Record<string, any>;
}): Promise<any[]>;
/**
* Finds a single entity by ID or key only
* @param entityType - Type of entity to find
* @param identifier - ID or key to search for
* @param projectId - Optional project ID for project-scoped entities
* @returns The found entity or null if not found
*/
findEntityByIdOrKey(entityType: EntityType, identifier: string, projectId?: string): Promise<any | null>;
/**
* Gets and caches project type information
* @param projectId - The project ID to check
* @returns Project type information with caching
*/
getProjectType(projectId: string): Promise<ProjectTypeInfo>;
/**
* Validates that a project exists and is accessible
* @param projectId - The project ID to validate
*/
validateProjectExists(projectId: string): Promise<void>;
/**
* Checks if cached project type information is still valid
*/
private isCacheValid;
/**
* Validates if an entity type is available for the given project type
* @param entityType - The entity type to validate
* @param projectType - The project type ('feature' or 'web')
* @param operation - The operation being performed
* @returns Error object if not available, null if available
*/
private validateEntityAvailability;
/**
* Gets available entities for a specific project type
*/
private getAvailableEntitiesForProject;
/**
* Suggests similar entities for the given project type
*/
private getSimilarEntitySuggestion;
/**
* Detects the platform for a given project (legacy method)
*/
detectPlatform(projectId: string): Promise<Platform>;
/**
* Lists all supported entity types
*/
getSupportedEntityTypes(): EntityType[];
/**
* Gets entity types for a specific platform
*/
getEntityTypesForPlatform(platform: Platform): EntityType[];
/**
* Handles enable operations for Feature Experimentation entities
*/
private handleEnableOperation;
/**
* Handles disable operations for Feature Experimentation entities
*/
private handleDisableOperation;
/**
* Handles history operations for Feature Experimentation entities
*/
private handleHistoryOperation;
/**
* Handles brainstorm operations (AI-powered suggestions)
*/
private handleBrainstormOperation;
/**
* Handles upload operations (bulk operations)
*/
private handleUploadOperation;
/**
* Handles bulk update operations for entity types that support them
*/
private handleBulkUpdateOperation;
/**
* Handles bulk archive operations for entity types that support them
*/
private handleBulkArchiveOperation;
/**
* Handles get results operations for experiments and campaigns
* @param entityType - Type of entity (experiment or campaign)
* @param projectId - Project ID (optional for some operations)
* @param entityId - Entity ID to get results for
* @param filters - Optional filters (date range, metrics, etc.)
* @param options - Additional options
* @returns Results data from the API
*/
private handleGetResultsOperation;
/**
* Enhances operation result with project type metadata
* @param result - The operation result to enhance
* @param projectId - Project ID if available
* @param entityType - Entity type for the operation
* @param operation - Operation that was performed
* @returns Enhanced result with metadata
*/
enhanceResultWithMetadata(result: any, projectId?: string, entityType?: EntityType, operation?: EntityOperation): Promise<any>;
/**
* Clears the project type cache
* @param projectId - Optional project ID to clear specific entry, or clear all if not provided
*/
clearProjectTypeCache(projectId?: string): void;
/**
* Gets cache statistics
*/
getCacheStats(): {
size: number;
entries: Array<{
projectId: string;
projectType: Platform;
lastChecked: Date;
isValid: boolean;
}>;
};
/**
* Gets a formatted error for unsupported entity/project combinations
* @param entityType - The entity type requested
* @param projectId - The project ID
* @param projectType - The project type
* @returns Formatted error object
*/
getEntityAvailabilityError(entityType: EntityType, projectId: string, projectType: Platform): any;
/**
* 🚨 SMART EXPERIMENT ROUTING - Handles experiment confusion intelligently
* When agent asks for 'experiment' on Feature Experimentation project, automatically redirect to flag approach
* @param projectId - The project ID to check
* @param filters - Original filters from the request
* @param options - Original options from the request
* @returns Enhanced result with flag-based experiment data and explanation
*/
private handleSmartExperimentRouting;
/**
* Extracts experiment-like data from flag configurations
* @param flags - Array of flags from the API
* @param projectId - Project ID for additional context
* @returns Array of experiment summaries extracted from flags
*/
private extractExperimentDataFromFlags;
/**
* Determines if a ruleset represents an A/B test experiment
* @param ruleset - The ruleset to analyze
* @returns true if this is an experiment, false if it's just targeted delivery
*/
private isRulesetAnExperiment;
/**
* Creates enhanced error messages with prescriptive guidance
* @param entityType - The entity type that failed
* @param projectId - Project ID if available
* @param originalError - The original error
* @param suggestions - Additional suggestions for the user
* @returns Enhanced MCP error with guidance
*/
private createEnhancedEntityError;
/**
* Build operation summary for enhanced metadata
* @param operation - The operation performed
* @param entityType - The entity type
* @param result - The operation result
* @param projectInfo - Project information
* @returns Summary object for metadata
*/
private buildOperationSummary;
/**
* Validates custom attributes in audience conditions and transforms for Web Experimentation
* @returns The potentially corrected/transformed conditions string
*/
private validateCustomAttributesInConditions;
/**
* Recursively extracts custom attribute references from audience conditions (platform-aware)
*/
private extractCustomAttributeReferences;
/**
* CRITICAL: Pre-validate payload for known validation issues before API call
* This prevents API-level validation failures by catching issues early and providing
* clear hard-stop errors that prevent infinite AI retry loops.
*/
private validatePayloadBeforeAPI;
/**
* Proactively syncs environments for a newly created project
* @param projectId - Project ID to sync environments for
* @description When a project is created, Optimizely automatically creates
* "production" and "development" environments. This method fetches them
* immediately from the API and stores them in the local database to avoid
* waiting for the next sync interval.
* @private
*/
private syncProjectEnvironments;
/**
* Convert variation_id fields from strings to integers for API compatibility
* The Optimizely API expects variation_id as integer, but template data may contain strings
*/
private convertVariationIdsToIntegers;
/**
* Helper method to debug variation_id types
*/
private getVariationIdTypes;
}
export {};
//# sourceMappingURL=EntityRouter.d.ts.map