Skip to main content
Glama

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