Skip to main content
Glama
JaxonDigital

Optimizely DXP MCP Server

by JaxonDigital

get_project

Retrieve detailed configuration for Optimizely DXP projects including environments, hosting type, and credential status to inspect settings or troubleshoot issues.

Instructions

šŸ“‹ Get detailed project configuration. REAL-TIME: <1s. Returns project ID, name, configured environments, hosting type (DXP/self-hosted), and credential validation status. Use to inspect project settings or troubleshoot configuration issues. Required: projectName. Returns full project config object.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
projectNameNo
projectIdNo

Implementation Reference

  • Handler function for the 'get_project' tool. Resolves a specific project by name or ID from configured projects, handles defaults, and returns formatted project information including type, credentials status, and configuration details.
    static getProject(args: { projectName?: string; projectId?: string }): any {
        const { projectName, projectId } = args;
        const projects = this.getConfiguredProjects();
    
        // Find the requested project
        let project: ProjectConfig | undefined;
        if (projectName || projectId) {
            project = projects.find(p =>
                p.name === projectName ||
                p.name?.toLowerCase() === projectName?.toLowerCase() ||
                p.projectId === projectId
            );
        } else {
            // Get default/current project
            project = this.getCurrentProject() || undefined;
        }
    
        if (!project) {
            const availableNames = projects.map(p => p.name).join(', ');
            return ResponseBuilder.formatResponse({
                success: false,
                message: `Project '${projectName || projectId}' not found`,
                details: availableNames ? `Available projects: ${availableNames}` : 'No projects configured'
            });
        }
    
        return this.formatProjectInfo(project, projects.length);
    }
  • Core helper method that discovers and parses all configured projects from environment variables and dynamic in-memory configs. Handles DXP PaaS, self-hosted, and unknown projects.
    static getConfiguredProjects(): ProjectConfig[] {
        // Dynamic configurations are kept in memory only for current session
    
        const projects: ProjectConfig[] = [];
        const configErrors: ConfigError[] = [];
    
        // Check ALL environment variables for our specific format
        // Any env var with format: "id=uuid;key=value;secret=value" is treated as an API key configuration
        // Examples:
        //   ACME="id=uuid;key=value;secret=value"
        //   PRODUCTION="id=uuid;key=value;secret=value"
        //   CLIENT_A_STAGING="id=uuid;key=value;secret=value"
    
        // DEBUG: Log all environment variables that contain our format
        const relevantEnvVars = Object.keys(process.env).filter(key => {
            const value = process.env[key];
            return value && typeof value === 'string' &&
                   ((value.includes('id=') && value.includes('key=') && value.includes('secret=')) ||
                    value.startsWith('DefaultEndpointsProtocol=') ||
                    ((value.includes('blobPath=') || value.includes('logPath=')) &&
                     !value.includes('id=') && !value.includes('key=') && !value.includes('secret=')));
        });
        OutputLogger.debug(`Checking environment variables...`);
        OutputLogger.debug(`Found ${relevantEnvVars.length} relevant env vars (DXP, self-hosted, and unknown):`, relevantEnvVars);
    
        Object.keys(process.env).forEach(key => {
            const value = process.env[key];
    
            // Skip if not a string
            if (typeof value !== 'string') {
                return;
            }
    
            // Check if empty string (placeholder project)
            // Only treat as project if name looks like a project name
            if (value === '') {
                // Skip if this doesn't look like a project name
                // Project names typically follow patterns like:
                // - "ACME-int", "CONTOSO-prod", "FABRIKAM-staging" (project-environment)
                // - "DEMO-self", "TEST-local" (project-type)
                // - Single short words like "zilch", "test", "demo"
    
                const hasProjectPattern =
                    // Pattern: WORD-env (like ACME-int, CONTOSO-prod)
                    key.match(/^[A-Z0-9]+-(?:int|prod|staging|test|dev|qa|uat|demo|local|self)$/i) ||
                    // Pattern: Short single word (max 10 chars)
                    (key.match(/^[A-Z0-9]+$/i) && key.length <= 10) ||
                    // Explicitly starts with common project prefixes
                    key.match(/^(?:TEST|DEMO|DEV|PROD|STAGING|QA)[-_]/i);
    
                if (!hasProjectPattern) {
                    return;
                }
    
                // Create Unknown placeholder project
                const projectName = key.replace(/_/g, ' ');
                const projectConfig: ProjectConfig = {
                    name: projectName,
                    projectId: `unknown-${projectName.toLowerCase().replace(/\s+/g, '-')}`,
                    isUnknown: true,
                    projectType: 'unknown',
                    needsConfiguration: true,
                    configurationHint: 'Empty project - add connectionString for self-hosted or id/key/secret for DXP',
                    environments: ['Unknown'],
                    configSource: 'environment'
                };
                projects.push(projectConfig);
                return;
            }
    
            // Check if this looks like our API key format OR a connection string OR self-hosted paths
            // Must contain either:
            // 1. DXP format: (id=, key=, secret=)
            // 2. Azure connection string: (DefaultEndpointsProtocol=)
            // 3. Self-hosted with paths only: (blobPath= or logPath=) but no id/key/secret
            const hasDxpFormat = value.includes('id=') && value.includes('key=') && value.includes('secret=');
            const hasConnectionString = value.startsWith('DefaultEndpointsProtocol=');
            const hasSelfHostedPaths = (value.includes('blobPath=') || value.includes('logPath=')) &&
                                       !value.includes('id=') && !value.includes('key=') && !value.includes('secret=');
    
            const hasCorrectFormat = hasDxpFormat || hasConnectionString || hasSelfHostedPaths;
    
            if (!hasCorrectFormat) {
                return;
            }
    
            // Use the environment variable name as the project name (underscores become spaces)
            const projectName = key.replace(/_/g, ' ');
    
            try {
                // Check if this is a raw Azure connection string (self-hosted mode)
                if (value.startsWith('DefaultEndpointsProtocol=')) {
                    // Extract connection string and any additional parameters
                    // Format: DefaultEndpointsProtocol=...;EndpointSuffix=core.windows.net;blobPath=/path;logPath=/path
    
                    // Find where the connection string ends (after EndpointSuffix)
                    const endpointMatch = value.match(/EndpointSuffix=[^;]+/);
                    let connectionString = value;
                    let additionalParams: Record<string, string> = {};
    
                    if (endpointMatch) {
                        const endIndex = value.indexOf(endpointMatch[0]) + endpointMatch[0].length;
                        connectionString = value.substring(0, endIndex);
    
                        // Parse any additional parameters after the connection string
                        const remaining = value.substring(endIndex);
                        if (remaining) {
                            const extraParts = remaining.split(';').filter(p => p.trim());
                            extraParts.forEach(part => {
                                const [key, val] = part.split('=');
                                if (key && val) {
                                    additionalParams[key] = val;
                                }
                            });
                        }
                    }
    
                    const projectConfig: ProjectConfig = {
                        name: projectName,
                        projectId: `self-hosted-${projectName.toLowerCase().replace(/\s+/g, '-')}`,
                        apiKey: '',
                        apiSecret: '',
                        connectionString: connectionString,
                        isSelfHosted: true,
                        environments: ['Production'], // Self-hosted typically has one environment
                        configSource: 'environment'
                    };
    
                    // Add optional paths if provided
                    if (additionalParams.blobPath) {
                        projectConfig.blobPath = additionalParams.blobPath;
                    }
                    if (additionalParams.logPath) {
                        projectConfig.logPath = additionalParams.logPath;
                    }
                    if (additionalParams.dbPath) {
                        projectConfig.dbPath = additionalParams.dbPath;
                    }
    
                    projects.push(projectConfig);
                    return;
                }
    
                // Otherwise parse semicolon-separated key=value pairs for DXP projects
                const params: Record<string, string> = {};
                const parts = value.split(';').filter(p => p.trim());
    
                if (parts.length === 0) {
                    // Empty configuration - treat as Unknown project placeholder
                    const projectConfig: ProjectConfig = {
                        name: projectName,
                        projectId: `unknown-${projectName.toLowerCase().replace(/\s+/g, '-')}`,
                        isUnknown: true,
                        projectType: 'unknown',
                        needsConfiguration: true,
                        configurationHint: 'Empty project - add connectionString for self-hosted or id/key/secret for DXP',
                        environments: ['Unknown'],
                        configSource: 'environment'
                    };
                    projects.push(projectConfig);
                    return;
                }
    
                parts.forEach(param => {
                    const equalIndex = param.indexOf('=');
                    if (equalIndex === -1) {
                        configErrors.push({
                            project: projectName,
                            error: `Invalid parameter format: "${param}" (expected key=value)`,
                            variable: key
                        });
                        return;
                    }
    
                    const paramKey = param.substring(0, equalIndex).trim();
                    const paramValue = param.substring(equalIndex + 1).trim();
    
                    if (!paramKey || !paramValue) {
                        configErrors.push({
                            project: projectName,
                            error: `Empty key or value in parameter: "${param}"`,
                            variable: key
                        });
                        return;
                    }
    
                    params[paramKey] = paramValue;
                });
    
                // Extract credentials using standard format
                let projectId = params.id;  // Changed to let to allow reassignment
                const apiKey = params.key;
                const apiSecret = params.secret;
                let connectionString = params.connectionString || params.connStr;
    
                // Check if this is a path-only project (has paths but no DXP credentials or connection string)
                const isPathOnlyProject = (params.blobPath || params.logPath || params.dbPath) &&
                                          !params.id && !params.key && !params.secret && !connectionString;
    
                // Determine project type and handle accordingly
                if (connectionString) {
                    // Self-hosted mode with connection string
                    if (!projectId) {
                        // Generate a simple ID from the project name
                        const projectIdBase = projectName.toLowerCase().replace(/\s+/g, '-');
                        projectId = `self-hosted-${projectIdBase}`;
                    }
                } else if (isPathOnlyProject) {
                    // Unknown type - has paths but no clear indication of type
                    if (!projectId) {
                        // Generate a simple ID from the project name
                        const projectIdBase = projectName.toLowerCase().replace(/\s+/g, '-');
                        projectId = `unknown-${projectIdBase}`;
                    }
                    OutputLogger.debug(`Unknown project type "${projectName}" configured with paths only`);
                } else if (!params.id || !params.key || !params.secret) {
                    // DXP mode - needs full API credentials
                    const missingFields: string[] = [];
                    if (!projectId) missingFields.push('id');
                    if (!apiKey) missingFields.push('key');
                    if (!apiSecret) missingFields.push('secret');
    
                    if (missingFields.length > 0) {
                        configErrors.push({
                            project: projectName,
                            error: `Missing required fields: ${missingFields.join(', ')}`,
                            variable: key,
                            hint: `Format: "id=<uuid>;key=<key>;secret=<secret>"`
                        });
                        return;
                    }
                }
    
                // Validate UUID format for project ID (skip for self-hosted and unknown)
                const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
                const isSelfHostedId = projectId && projectId.startsWith('self-hosted-');
                const isUnknownId = projectId && projectId.startsWith('unknown-');
                if (!isSelfHostedId && !isUnknownId && !uuidRegex.test(projectId!)) {
                    configErrors.push({
                        project: projectName,
                        error: `Invalid project ID format: "${projectId}"`,
                        variable: key,
                        hint: `Project ID should be a UUID like: abc12345-1234-5678-9abc-def123456789`
                    });
                }
    
                // Validate environments if specified
                if (params.environments) {
                    const validEnvs = ['Integration', 'Preproduction', 'Production'];
                    const envs = params.environments.split(',').map(e => e.trim());
                    const invalidEnvs = envs.filter(e => !validEnvs.includes(e));
    
                    if (invalidEnvs.length > 0) {
                        configErrors.push({
                            project: projectName,
                            error: `Invalid environments: ${invalidEnvs.join(', ')}`,
                            variable: key,
                            hint: `Valid environments are: Integration, Preproduction, Production`
                        });
                    }
                }
    
                // Add project if validation passed
                const projectConfig: ProjectConfig = {
                    name: projectName,
                    projectId: projectId!,
                    apiKey: apiKey || '',
                    apiSecret: apiSecret || '',
                    environments: params.environments
                        ? params.environments.split(',').map(e => e.trim())
                        : ['Integration', 'Preproduction', 'Production'],
                    configSource: 'environment'
                };
    
                // Determine project type based on available credentials
                if (connectionString) {
                    // Self-hosted with connection string
                    projectConfig.connectionString = connectionString;
                    projectConfig.isSelfHosted = true;
                    projectConfig.projectType = 'self-hosted';
                } else if (isPathOnlyProject) {
                    // Unknown type - has paths but no credentials
                    projectConfig.isUnknown = true;
                    projectConfig.projectType = 'unknown';
                    projectConfig.needsConfiguration = true;
                    // For unknown projects, we need to guide users to add credentials
                    projectConfig.configurationHint = 'Add connectionString for self-hosted or id/key/secret for DXP';
                } else if (apiKey && apiSecret) {
                    // DXP PaaS project
                    projectConfig.projectType = 'dxp-paas';
                }
    
                // Add compact configuration fields if present
                if (params.blobPath) {
                    projectConfig.blobPath = params.blobPath;
                }
                if (params.dbPath) {
                    projectConfig.dbPath = params.dbPath;
                }
                if (params.logPath) {
                    projectConfig.logPath = params.logPath;
                }
                if (params.telemetry) {
                    projectConfig.telemetry = params.telemetry.toLowerCase() === 'true';
                }
    
                projects.push(projectConfig);
    
            } catch (error: any) {
                configErrors.push({
                    project: projectName,
                    error: `Failed to parse configuration: ${error.message}`,
                    variable: key
                });
            }
        });
    
        // Log configuration errors if any
        if (configErrors.length > 0) {
            console.error('\nāš ļø  Configuration Errors Found:');
            configErrors.forEach(err => {
                console.error(`\n  Project: ${err.project}`);
                console.error(`  Variable: ${err.variable}`);
                console.error(`  Error: ${err.error}`);
                if (err.hint) {
                    console.error(`  Hint: ${err.hint}`);
                }
                if (err.value) {
                    console.error(`  Value: ${err.value.substring(0, 50)}...`);
                }
            });
            console.error('\n');
        }
    
        // Add dynamically added configurations
        this.dynamicConfigurations.forEach(dynConfig => {
            // Check if this dynamic config should replace an existing project
            const existingIndex = projects.findIndex(p => {
                // Match by original name (for renames)
                if (dynConfig.originalName && p.name === dynConfig.originalName) {
                    return true;
                }
                // Match by current name
                if (p.name === dynConfig.name || p.name.toLowerCase() === dynConfig.name.toLowerCase()) {
                    return true;
                }
                // Match by project ID
                if (p.projectId === dynConfig.projectId) {
                    return true;
                }
                return false;
            });
    
            if (existingIndex >= 0) {
                // Replace existing project with dynamic configuration (upgrade/rename scenario)
                projects[existingIndex] = dynConfig;
            } else if (!projects.find(p => p.projectId === dynConfig.projectId)) {
                // Only add if not already in list (avoid duplicates by ID)
                projects.push(dynConfig);
            }
        });
    
        // First project is always the default (simplified logic)
    
        // DEBUG: Log final projects found
        OutputLogger.debug('Final projects found:');
        projects.forEach((p, i) => {
            OutputLogger.debug(`  ${i + 1}. Name: "${p.name}", ID: ${p.projectId || 'undefined'}, Source: ${p.configSource || 'unknown'}`);
        });
    
        return projects;
    }
  • Type definition for arguments accepted by project tools, including get_project.
    interface GetProjectArgs {
        projectName?: string;
        projectId?: string;
        apiKey?: string;
        apiSecret?: string;
        connectionString?: string;
        renameTo?: string;
    }
  • Tool availability registration for 'get_project' - defines supported hosting types and category.
    'get_project': {
        hostingTypes: ['dxp-paas', 'dxp-saas', 'self-hosted', 'unknown'],
        category: 'Project Management',
        description: 'Get project information and configuration details'
  • Helper to show current/active project configuration, used in project resolution.
    static async showCurrentProject(): Promise<any> {
        try {
            // Check for last used project first (from switch_project)
            let currentProject: ProjectConfig | null = null;
            const lastUsed = process.env.MCP_LAST_USED_PROJECT;
    
            if (lastUsed) {
                const projects = this.getConfiguredProjects();
                currentProject = projects.find(p =>
                    p.name === lastUsed ||
                    p.name.toLowerCase() === lastUsed.toLowerCase()
                ) || null;
            }
    
            // Fall back to default (first project)
            if (!currentProject) {
                currentProject = this.getCurrentProject();
            }
    
            if (!currentProject) {
                return ResponseBuilder.error('No project currently selected');
            }
    
            let response = `šŸ“Œ **Current Project: ${currentProject.name}**\n\n`;
            response += `• Project ID: ${currentProject.projectId}\n`;
    
            // Show project type
            if (currentProject.isSelfHosted) {
                response += `• Type: Self-hosted Azure\n`;
                response += `• Environment: Production\n`;
            } else if (currentProject.isUnknown) {
                response += `• Type: Unconfigured\n`;
                response += `• Status: Needs API credentials or connection string\n`;
            } else {
                response += `• Type: DXP PaaS\n`;
                response += `• Configured Environments: ${currentProject.environments ? currentProject.environments.join(', ') : 'N/A'}\n`;
                response += `• Note: Use \`test_connection\` to check actual permissions\n`;
            }
    
            response += `${currentProject.isDefault ? '• Default: Yes ⭐\n' : ''}`;
    
            return ResponseBuilder.success(response);
        } catch (error: any) {
            return ResponseBuilder.error(`Failed to get current project: ${error.message}`);
        }
    }

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