Skip to main content
Glama
JaxonDigital

Optimizely DXP MCP Server

by JaxonDigital

switch_project

Change the active project context in multi-project Optimizely DXP setups to set default credentials and project ID for all subsequent operations. Use before managing multiple projects to ensure commands target the correct environment.

Instructions

🔄 Switch active project context for multi-project setups. INSTANT: <1s. Changes default credentials and project ID for all subsequent tool calls. Use this before operations when managing multiple Optimizely projects. Project context persists for entire session. Required: projectName. Returns new active project details. Use list_projects() to see available projects.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
projectNameYesName of the project to switch to

Implementation Reference

  • Main handler function that executes the switch_project tool logic: validates input, lists projects, calls ProjectTools.switchProject, handles errors with fuzzy matching suggestions, and returns structured success/error responses.
    static async handleSwitchProject(args: ProjectSwitchArgs): Promise<any> {
        const { projectName } = args;
    
        if (!projectName) {
            return ResponseBuilder.error(
                '❌ Project name is required',
                { error: 'Missing projectName parameter' }
            );
        }
    
        try {
            // DXP-36: Improved error handling for project switching
    
            // First, try to get available projects with error handling
            let projects;
            try {
                projects = ProjectTools.getConfiguredProjects();
            } catch (configError: any) {
                return ResponseBuilder.error(
                    '❌ **Configuration Error**\n\n' +
                    'Unable to load project configurations. This might be due to:\n' +
                    '• Malformed environment variables\n' +
                    '• Invalid project configuration format\n' +
                    '• Missing required configuration fields\n\n' +
                    `**Error details**: ${configError.message}\n\n` +
                    '💡 **Next steps**:\n' +
                    '1. Check your environment variables for proper format\n' +
                    '2. Use `list_projects` to see current configuration status\n' +
                    '3. Refer to setup documentation for correct format',
                    {
                        error: 'Configuration load failed',
                        details: configError.message,
                        requestedProject: projectName
                    }
                );
            }
    
            if (!projects || projects.length === 0) {
                return ResponseBuilder.error(
                    '❌ **No Projects Configured**\n\n' +
                    'No projects are currently configured in your environment.\n\n' +
                    '💡 **To configure a project**, add an environment variable like:\n' +
                    '```\n' +
                    'MYPROJECT="id=your-project-id;key=your-api-key;secret=your-secret"\n' +
                    '```\n\n' +
                    'Or see the setup guide for detailed instructions.',
                    {
                        error: 'No projects configured',
                        requestedProject: projectName,
                        availableProjects: []
                    }
                );
            }
    
            // Attempt to switch project
            const result = ProjectTools.switchProject(projectName);
    
            if (!result.success) {
                // DXP-36: Enhanced error message with fuzzy matching and better suggestions
                const projectNames = projects.map((p: any) => p.name).filter(Boolean);
    
                // Find closest matches using simple string similarity
                const closeMatches = this.findSimilarProjectNames(projectName, projectNames);
    
                let errorMessage = `❌ **Project "${projectName}" not found**\n\n`;
    
                if (closeMatches.length > 0) {
                    errorMessage += `🔍 **Did you mean?**\n${closeMatches.map(name => `  • ${name}`).join('\n')}\n\n`;
                }
    
                errorMessage += `📋 **Available projects** (${projectNames.length}):\n`;
                if (projectNames.length <= 10) {
                    errorMessage += `${projectNames.map((n: string) => `  • ${n}`).join('\n')}\n\n`;
                } else {
                    errorMessage += `${projectNames.slice(0, 8).map((n: string) => `  • ${n}`).join('\n')}\n  • ... and ${projectNames.length - 8} more\n\n`;
                    errorMessage += `💡 Use \`list_projects\` to see all projects\n\n`;
                }
    
                errorMessage += `💡 **Tips**:\n`;
                errorMessage += `• Project names are case-insensitive\n`;
                errorMessage += `• You can use partial names if unique\n`;
                errorMessage += `• Check for typos in the project name`;
    
                return ResponseBuilder.error(
                    errorMessage,
                    {
                        requestedProject: projectName,
                        availableProjects: projectNames,
                        suggestions: closeMatches,
                        totalProjects: projectNames.length
                    }
                );
            }
    
            // Success! Set as last used project for session persistence
            ProjectTools.setLastUsedProject(projectName);
    
            // Get project details for confirmation
            const project = result.project!;
    
            return ResponseBuilder.successWithStructuredData(
                {
                    projectName: project.name,
                    projectId: project.projectId,
                    isDefault: project.isDefault || false
                },
                `✅ **Switched to ${project.name}**\n\n` +
                `**Project Details**:\n` +
                `• Project ID: ${project.projectId}\n` +
                `• Environments: ${project.environments!.join(', ')}\n` +
                `• Status: Active\n\n` +
                `📌 All subsequent commands will use this project until you switch again.\n\n` +
                `💡 **Tip**: You can also include the project name in any command:\n` +
                `   Example: \`list_deployments --project "${project.name}"\``
            );
    
        } catch (switchError: any) {
            // DXP-36: Handle unexpected errors during project switching
            return ResponseBuilder.error(
                '❌ **Unexpected Error During Project Switch**\n\n' +
                `An unexpected error occurred while switching to project "${projectName}".\n\n` +
                `**Error details**: ${switchError.message}\n\n` +
                '💡 **Troubleshooting**:\n' +
                '1. Check if the project configuration is valid\n' +
                '2. Verify environment variables are properly set\n' +
                '3. Try switching to a different project first\n' +
                '4. Contact support if the issue persists',
                {
                    error: 'Unexpected switch error',
                    details: switchError.message,
                    requestedProject: projectName
                }
            );
        }
    }
  • TypeScript interface defining the input arguments for the switch_project tool.
    interface ProjectSwitchArgs {
        projectName?: string;
    }
  • Core helper method that performs the actual project switching: finds project by name/ID (case-insensitive), returns credentials and project info, or error if not found. Used by the handler.
    static switchProject(projectIdentifier: string | { projectName?: string; project?: string; projectId?: string }): SwitchResult {
        // Handle both string and object input
        const identifier = typeof projectIdentifier === 'object'
            ? (projectIdentifier.projectName || projectIdentifier.project || projectIdentifier.projectId)
            : projectIdentifier;
    
        if (!identifier) {
            return {
                success: false,
                message: 'No project identifier provided',
                credentials: null
            };
        }
    
        const projects = this.getConfiguredProjects();
    
        const project = projects.find(p =>
            p.projectId === identifier ||
            p.name === identifier ||
            p.name.toLowerCase() === identifier.toLowerCase()
        );
    
        if (!project) {
            return {
                success: false,
                message: `Project '${projectIdentifier}' not found`,
                credentials: null
            };
        }
    
        return {
            success: true,
            message: `Switched to project: ${project.name}`,
            credentials: {
                projectId: project.projectId,
                apiKey: project.apiKey,
                apiSecret: project.apiSecret
            },
            project: project
        };
    }
  • Fuzzy matching helper for suggesting similar project names when exact match fails, used in error handling.
    static findSimilarProjectNames(input: string, projectNames: string[], maxSuggestions: number = 3): string[] {
        if (!input || !projectNames || projectNames.length === 0) {
            return [];
        }
    
        const inputLower = input.toLowerCase();
        const suggestions: SimilaritySuggestion[] = [];
    
        for (const name of projectNames) {
            const nameLower = name.toLowerCase();
            let score = 0;
    
            // Exact match (shouldn't happen, but just in case)
            if (nameLower === inputLower) {
                continue;
            }
    
            // Starts with input
            if (nameLower.startsWith(inputLower)) {
                score = 90;
            }
            // Contains input
            else if (nameLower.includes(inputLower)) {
                score = 70;
            }
            // Input contains project name (partial)
            else if (inputLower.includes(nameLower)) {
                score = 60;
            }
            // Check if input is close to start of project name (abbreviation-like)
            else if (inputLower.length <= 4 && nameLower.length >= inputLower.length) {
                // Check if most characters of input match start of name
                let matches = 0;
                for (let i = 0; i < Math.min(inputLower.length, nameLower.length); i++) {
                    if (inputLower[i] === nameLower[i]) {
                        matches++;
                    }
                }
                if (matches >= inputLower.length - 1) { // Allow 1 mismatch
                    score = 50;
                }
            }
            // Levenshtein-like simple distance
            else {
                const distance = this.simpleEditDistance(inputLower, nameLower);
                const maxLen = Math.max(inputLower.length, nameLower.length);
                const similarity = Math.max(0, (maxLen - distance) / maxLen);
    
                // Be more lenient with shorter inputs - they often are abbreviations
                const threshold = inputLower.length <= 4 ? 0.4 : 0.5;
    
                if (similarity > threshold) {
                    score = Math.floor(similarity * 50);
                }
            }
    
            if (score > 0) {
                suggestions.push({ name, score });
            }
        }
    
        // Sort by score (highest first) and return top suggestions
        return suggestions
            .sort((a, b) => b.score - a.score)
            .slice(0, maxSuggestions)
            .map(s => s.name);
    }
  • NLP pattern registration that maps natural language like 'switch to project X' to the 'switch_project' tool.
    { pattern: /^(switch|change|use).*(project|client|api)/i, tool: 'switch_project', category: 'setup' },

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/JaxonDigital/optimizely-dxp-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server