@simonecoelhosfo/optimizely-mcp-server
Version:
Optimizely MCP Server for AI assistants with integrated CLI tools
583 lines • 21.9 kB
JavaScript
/**
* Entity Creation Templates
* @description Comprehensive templates for creating Optimizely entities with placeholder-based approach.
* AI agents fill in {FILL: description} placeholders instead of guessing API structures.
*
* Template Philosophy:
* - {FILL: description} = Required field that AI agent must fill
* - {OPTIONAL: description} = Optional field that can be omitted
* - Platform-specific templates based on is_flags_enabled project property
*
* @author Optimizely MCP Server
* @version 1.0.0
*/
/**
* Comprehensive Entity Creation Templates
* Organized by complexity and platform availability
*/
export const ENTITY_TEMPLATES = {
// =============================================================================
// FEATURE EXPERIMENTATION TEMPLATES (is_flags_enabled: true)
// =============================================================================
/**
* Flag Creation Template - MINIMAL
* Creates flag without variables or A/B test
* For complex flags with variables/AB test, use advanced templates
*/
flag: {
metadata: {
platform: 'feature',
complexity: 'minimal',
description: 'Create a basic feature flag',
requiredFields: ['key', 'name'],
optionalFields: [],
apiCalls: 1,
dependencies: []
},
template: {
key: '{FILL: unique_flag_key_no_spaces}',
name: '{FILL: display_name}'
}
},
/**
* Flag with Variables Template
* Creates flag with variable definitions
*/
flag_with_variables: {
metadata: {
platform: 'feature',
complexity: 'medium',
description: 'Create a feature flag with variables',
requiredFields: ['flag.key', 'flag.name'],
optionalFields: ['variables'],
apiCalls: 2, // flag + variables
dependencies: []
},
template: {
flag: {
key: '{FILL: unique_flag_key_no_spaces}',
name: '{FILL: display_name}'
},
variables: [
{
key: '{FILL: variable_key}',
type: '{FILL_ENUM: string|boolean|integer|double|json}',
default_value: '{FILL: default_value_matching_type}'
}
]
}
},
/**
* ❌ REMOVED: flag_with_ab_test template - INVALID PATTERN
*
* This template was teaching agents to use the incorrect 'ab_test' structure
* on Feature Experimentation flags, which doesn't exist in the API.
*
* ✅ CORRECT APPROACH for A/B tests in Feature Experimentation:
*
* 1. Create the flag with variables (use flag_with_variables template)
* 2. Create variations separately (entity_type='variation')
* 3. Update the ruleset to add A/B test rules (entity_type='ruleset')
* 4. Create experiment for tracking (entity_type='experiment')
*
* This multi-step approach is the ONLY way to create A/B tests in Feature Experimentation.
* The 'ab_test' field does not exist on flags and was causing validation errors.
*
* For working examples, see:
* - docs/agent-education/update-flag-ab-test-example.md (corrected approach)
* - Use separate templates for each step instead of this combined approach
*/
/**
* Event Creation Template - Feature Experimentation
* Creates metrics for A/B test measurement
* NOTE: All fields are optional in the API
*/
event: {
metadata: {
platform: 'feature',
complexity: 'simple',
description: 'Create an event/metric for measuring A/B test results',
requiredFields: [], // No required fields per API spec
optionalFields: ['key', 'name', 'event_type', 'event_properties'],
apiCalls: 1
},
template: {
key: '{FILL: unique_event_key}',
name: '{FILL: display_name}',
event_type: '{FILL_ENUM: custom|click|pageview|conversion}'
}
},
/**
* Event with Properties Template - Feature Experimentation
* Creates an event with event properties for advanced filtering
*/
event_with_properties: {
metadata: {
platform: 'feature',
complexity: 'simple',
description: 'Create an event with properties for metrics filtering',
requiredFields: [], // No required fields per API spec
optionalFields: ['key', 'name', 'event_type', 'event_properties'],
apiCalls: 1
},
template: {
_template_type: 'event_with_properties',
key: '{FILL: unique_event_key}',
name: '{FILL: display_name}',
event_type: '{FILL_ENUM: custom|click|pageview|conversion}',
event_properties: [
{
name: '{FILL: property_name}',
data_type: '{FILL_ENUM: string|number|boolean}',
description: '{OPTIONAL: property_description}'
}
]
}
},
// =============================================================================
// WEB EXPERIMENTATION TEMPLATES (is_flags_enabled: false)
// =============================================================================
/**
* Page Creation Template - Web Experimentation
* Creates pages for experiment targeting
*/
page: {
metadata: {
platform: 'web',
complexity: 'minimal',
description: 'Create a page for web experimentation targeting',
requiredFields: ['name', 'edit_url'], // project_id added automatically
optionalFields: [],
apiCalls: 1
},
template: {
name: '{FILL: page_name}',
edit_url: '{FILL: target_url}'
}
},
/**
* Page with Conditions Template
* Creates page with activation and targeting conditions
*/
page_with_conditions: {
metadata: {
platform: 'web',
complexity: 'medium',
description: 'Create a page with targeting conditions',
requiredFields: ['name', 'edit_url'],
optionalFields: ['activation_type', 'conditions'],
apiCalls: 1
},
template: {
name: '{FILL: page_name}',
edit_url: '{FILL: target_url}',
activation_type: '{FILL_ENUM: immediate|manual|polling|callback|dom_changed|url_changed}',
conditions: '["and", {"type": "url", "match_type": "{FILL_ENUM: exact|simple|substring|regex}", "value": "{FILL: url_pattern}"}]'
},
examples: [
{
name: 'Homepage',
edit_url: 'https://example.com/',
activation_type: 'immediate',
conditions: '["and", {"type": "url", "match_type": "exact", "value": "https://example.com/"}]'
},
{
name: 'Product Pages',
edit_url: 'https://example.com/products/',
activation_type: 'dom_changed',
conditions: '["and", {"type": "url", "match_type": "substring", "value": "/products/"}]'
}
]
},
/**
* Web Experiment Creation Template - MINIMAL
* Creates experiment container only
* WARNING: Must add variations separately or use experiment_with_variations
*/
experiment: {
metadata: {
platform: 'web',
complexity: 'minimal',
description: 'Create a web experiment container',
requiredFields: [], // Only project_id required (added automatically)
optionalFields: ['name', 'page_ids'],
apiCalls: 1,
dependencies: ['page']
},
template: {
name: '{FILL: experiment_name}',
page_ids: ['{FILL: page_id_from_page_creation}']
}
},
/**
* Web Experiment with Variations Template
* Creates complete experiment with variations
* CRITICAL: All variations MUST have actions with changes
*/
experiment_with_variations: {
metadata: {
platform: 'web',
complexity: 'medium',
description: 'Create a complete web experiment with variations',
requiredFields: ['variations[].weight'], // Variations must have weight
optionalFields: ['name', 'page_ids'],
apiCalls: 2, // experiment + variations
dependencies: ['page']
},
template: {
name: '{FILL: experiment_name}',
page_ids: ['{FILL: page_id_from_page_creation}'],
variations: [
{
name: '{FILL: Control}',
weight: '{FILL: basis_points_10000=100%}', // Must sum to 10000 across all variations
// For 3 variations: use 3333, 3333, 3334
// For 4+ variations: divide 10000 evenly, give remainder to last variations
actions: [] // Changes will be added later in the Optimizely UI
},
{
name: '{FILL: Treatment}',
weight: '{FILL: basis_points_10000=100%}',
actions: [] // Changes will be added later in the Optimizely UI
}
],
metrics: [
{
event_id: '{FILL: integer_event_id}', // ⚠️ CRITICAL: Must be integer ID of existing event
aggregator: '{REQUIRED_ENUM: "unique" | "count" | "sum" | "bounce" | "exit" | "ratio"}', // ⚠️ CRITICAL: Must use EXACT value from this list
scope: '{REQUIRED_ENUM: "session" | "visitor" | "event"}', // ⚠️ CRITICAL: Must use EXACT value from this list
winning_direction: '{OPTIONAL_ENUM: "increasing" | "decreasing"}' // Optional, defaults to "increasing"
}
]
},
examples: [
{
name: 'Homepage Hero Test',
description: 'Test different hero section copy',
page_ids: ['12345'],
variations: [
{
name: 'Control',
weight: 5000,
actions: [] // No changes for Control - defined later in UI
},
{
name: 'New Hero Copy',
weight: 5000,
actions: [
{
page_id: 12345,
changes: [
{
type: 'insert_html',
selector: '.hero-title',
value: '<h1>Revolutionary New Product</h1>'
}
]
}
]
}
]
},
{
name: 'Three-Way Button Test Example',
description: 'Testing three different button colors',
page_ids: ['12345'],
variations: [
{
name: 'Blue Button',
weight: 3333,
actions: [
{
page_id: 12345,
changes: [
{
type: 'replace_html',
selector: '.cta-button',
value: '<button class="blue">Get Started</button>'
}
]
}
]
},
{
name: 'Green Button',
weight: 3333,
actions: [
{
page_id: 12345,
changes: [
{
type: 'replace_html',
selector: '.cta-button',
value: '<button class="green">Get Started</button>'
}
]
}
]
},
{
name: 'Red Button',
weight: 3334, // Gets the extra basis point
actions: [
{
page_id: 12345,
changes: [
{
type: 'replace_html',
selector: '.cta-button',
value: '<button class="red">Get Started</button>'
}
]
}
]
}
]
}
]
},
/**
* Campaign Creation Template - Web Experimentation
* Creates campaigns for grouping experiments
*/
campaign: {
metadata: {
platform: 'web',
complexity: 'minimal',
description: 'Create a campaign for organizing experiments',
requiredFields: [], // Only project_id required (added automatically)
optionalFields: ['name'],
apiCalls: 1
},
template: {
name: '{FILL: campaign_name}'
},
examples: [
{
name: 'Q4 Homepage Optimization',
description: 'Testing different homepage elements for Q4',
page_ids: ['12345'],
holdback: '1000'
},
{
// Example with entity reference (Phase 3)
name: 'Multi-Page Campaign',
description: 'Campaign across multiple existing pages',
page_ids: [
'{EXISTING: page:homepage}',
'{EXISTING: page:product_list}',
'{FIND_OR_CREATE: page:checkout}'
],
holdback: '500'
}
]
},
// =============================================================================
// SHARED TEMPLATES (Both platforms)
// =============================================================================
/**
* Audience Creation Template - Both Platforms
* Creates audience segments for targeting
*/
audience: {
metadata: {
platform: 'both',
complexity: 'minimal',
description: 'Create a basic audience',
requiredFields: [], // Only project_id required (added automatically)
optionalFields: ['name'],
apiCalls: 1
},
template: {
name: '{FILL: audience_name}'
}
},
/**
* Audience with Conditions Template
* Creates audience with targeting conditions
*/
audience_with_conditions: {
metadata: {
platform: 'both',
complexity: 'medium',
description: 'Create an audience with targeting conditions',
requiredFields: [],
optionalFields: ['name', 'conditions'],
apiCalls: 1
},
template: {
name: '{FILL: audience_name}',
conditions: [
'and',
{
type: '{FILL_ENUM: browser|location|custom_attribute|device}',
name: '{FILL: condition_parameter}',
value: '{FILL: condition_value}'
}
]
},
examples: [
{
name: 'US Mobile Users',
description: 'Users on mobile devices in the United States',
conditions: [
'and',
{
type: 'location',
name: 'country',
value: 'US'
},
{
type: 'device',
name: 'mobile',
value: 'true'
}
]
}
]
},
/**
* Attribute Creation Template - Both Platforms
* Creates custom attributes for audience targeting
*/
attribute: {
metadata: {
platform: 'both',
complexity: 'minimal',
description: 'Create a custom attribute',
requiredFields: ['key'], // project_id added automatically
optionalFields: ['name'],
apiCalls: 1
},
template: {
key: '{FILL: attribute_key_no_spaces}',
name: '{FILL: display_name}'
},
examples: [
{
key: 'user_tier',
name: 'User Tier',
description: 'Customer tier level (bronze, silver, gold)',
condition_type: 'single_option'
}
]
},
/**
* Webhook Creation Template - Both Platforms
* Creates webhooks for event notifications
*/
webhook: {
metadata: {
platform: 'both',
complexity: 'minimal',
description: 'Create a webhook for notifications',
requiredFields: ['name', 'url'], // project_id added automatically
optionalFields: ['event_types'],
apiCalls: 1
},
template: {
name: '{FILL: webhook_name}',
url: '{FILL: https_endpoint_url}',
event_types: ['{FILL_ENUM: experiment.created|experiment.modified|decision.notification}']
},
examples: [
{
name: 'Slack Notifications',
url: 'https://hooks.slack.com/services/YOUR/SLACK/WEBHOOK',
event_types: ['experiment.created', 'experiment.modified'],
headers: {
'Content-Type': 'application/json'
}
}
]
},
/**
* Extension Creation Template - Web Experimentation
* Creates custom JavaScript extensions
*/
extension: {
metadata: {
platform: 'web',
complexity: 'minimal',
description: 'Create a JavaScript extension',
requiredFields: ['name', 'edit_url', 'implementation'], // per API spec
optionalFields: [],
apiCalls: 1
},
template: {
name: '{FILL: extension_name}',
edit_url: '{FILL: editor_url}',
implementation: '{FILL: javascript_code_string}'
},
examples: [
{
name: 'Google Analytics Integration',
description: 'Send experiment data to Google Analytics',
extension_type: 'analytics_integration',
implementation: `
window.optimizely = window.optimizely || [];
window.optimizely.push({
type: "analytics",
provider: "google",
measurementId: "GA_MEASUREMENT_ID"
});
`
}
]
}
};
/**
* Get templates available for a specific platform
* @param isFeatureExperimentation - Whether project has Feature Experimentation enabled
* @returns Available entity templates for the platform
*/
export function getAvailableTemplates(isFeatureExperimentation) {
const availableTemplates = {};
for (const [entityType, template] of Object.entries(ENTITY_TEMPLATES)) {
const { platform } = template.metadata;
if (platform === 'both') {
availableTemplates[entityType] = template;
}
else if (platform === 'feature' && isFeatureExperimentation) {
availableTemplates[entityType] = template;
}
else if (platform === 'web' && !isFeatureExperimentation) {
availableTemplates[entityType] = template;
}
}
return availableTemplates;
}
/**
* Get template placeholders that need to be filled
* @param template - Template object to analyze
* @returns Array of placeholder descriptions
*/
export function getTemplatePlaceholders(template) {
const placeholders = [];
function extractPlaceholders(obj, path = '') {
if (typeof obj === 'string') {
const fillMatch = obj.match(/\{FILL:\s*([^}]+)\}/);
const optionalMatch = obj.match(/\{OPTIONAL:\s*([^}]+)\}/);
if (fillMatch) {
placeholders.push(`${path}: ${fillMatch[1]} (REQUIRED)`);
}
else if (optionalMatch) {
placeholders.push(`${path}: ${optionalMatch[1]} (OPTIONAL)`);
}
}
else if (Array.isArray(obj)) {
obj.forEach((item, index) => {
extractPlaceholders(item, `${path}[${index}]`);
});
}
else if (obj && typeof obj === 'object') {
Object.entries(obj).forEach(([key, value]) => {
const newPath = path ? `${path}.${key}` : key;
extractPlaceholders(value, newPath);
});
}
}
extractPlaceholders(template);
return placeholders;
}
//# sourceMappingURL=EntityTemplates.js.map