Skip to main content
Glama
JaxonDigital

Optimizely DXP MCP Server

by JaxonDigital

update_project

Modify Optimizely DXP project configuration settings including credentials, name, and environment parameters to maintain operational continuity across deployment environments.

Instructions

✏️ Update project configuration settings. INSTANT: <1s. Modifies stored credentials, project name, or environment settings. Changes persist for session. Use with caution - invalid credentials will break subsequent operations. Required: projectName, updates (object with fields to change). Returns updated project config. Test with test_connection() after updating.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
projectNameNo
projectIdNo
renameToNo
apiKeyNo
apiSecretNo
connectionStringNo
blobPathNo
dbPathNo
logPathNo
makeDefaultNoSet this project as default for getCurrentProject() - auto-enabled when providing inline credentials

Implementation Reference

  • Core handler for the 'update_project' tool. Updates project configuration including renaming, credentials (API key/secret or connection string), paths (blob/db/log), and settings (make default). Handles project type conversions (DXP PaaS ↔ Self-Hosted ↔ Unknown). Uses dynamic in-memory configuration storage.
    static updateProject(args: UpdateProjectArgs): any {
        const {
            projectName,
            projectId,
            // Rename
            renameTo,
            // Credentials
            apiKey,
            apiSecret,
            connectionString,
            // Paths
            blobPath,
            dbPath,
            logPath,
            // Settings
            makeDefault
        } = args;
    
        // Find the project to update
        const projects = this.getConfiguredProjects();
        const project = projects.find(p =>
            p.name === projectName ||
            p.name?.toLowerCase() === projectName?.toLowerCase() ||
            p.projectId === projectId
        );
    
        if (!project) {
            // If no existing project, create new one if we have enough info
            if (projectName && (apiKey || connectionString)) {
                return this.getProjectInfo(args as GetProjectArgs); // Use existing creation logic
            }
    
            return ResponseBuilder.formatResponse({
                success: false,
                message: `Project '${projectName || projectId}' not found`,
                details: 'Specify an existing project to update or provide credentials to create a new one'
            });
        }
    
        // Build updated configuration
        const updatedConfig: ProjectConfig = { ...project };
        let changes: string[] = [];
    
        // Handle rename
        if (renameTo && renameTo !== project.name) {
            updatedConfig.name = renameTo;
            updatedConfig.originalName = project.name;
            changes.push(`Renamed from '${project.name}' to '${renameTo}'`);
        }
    
        // Handle credentials update
        if (apiKey && apiKey !== project.apiKey) {
            updatedConfig.apiKey = apiKey;
            changes.push('Updated API key');
            // If providing API credentials, this becomes a DXP project
            if (apiSecret) {
                if (project.projectType === 'self-hosted' || project.isSelfHosted) {
                    changes.push('Converted from Self-Hosted to DXP PaaS');
                }
                updatedConfig.projectType = 'dxp-paas';
                updatedConfig.isSelfHosted = false;
                delete updatedConfig.connectionString;
                updatedConfig.environments = ['Integration', 'Preproduction', 'Production'];
            }
        }
        if (apiSecret && apiSecret !== project.apiSecret) {
            updatedConfig.apiSecret = apiSecret;
            changes.push('Updated API secret');
            // If providing API credentials, this becomes a DXP project
            if (apiKey || updatedConfig.apiKey) {
                if (project.projectType === 'self-hosted' || project.isSelfHosted) {
                    changes.push('Converted from Self-Hosted to DXP PaaS');
                }
                updatedConfig.projectType = 'dxp-paas';
                updatedConfig.isSelfHosted = false;
                delete updatedConfig.connectionString;
                updatedConfig.environments = ['Integration', 'Preproduction', 'Production'];
            }
        }
        if (connectionString && connectionString !== project.connectionString) {
            updatedConfig.connectionString = connectionString;
            if (project.projectType === 'dxp-paas' || (!project.isSelfHosted && project.apiKey)) {
                changes.push('Converted from DXP PaaS to Self-Hosted');
            }
            updatedConfig.isSelfHosted = true;
            updatedConfig.projectType = 'self-hosted';
            updatedConfig.environments = ['Production'];
            // Remove DXP-specific fields
            delete updatedConfig.apiKey;
            delete updatedConfig.apiSecret;
            changes.push('Updated connection string');
        }
    
        // Handle project ID update (for DXP projects)
        if (projectId && projectId !== project.projectId && !project.projectId.startsWith('unknown-')) {
            updatedConfig.projectId = projectId;
            changes.push('Updated project ID');
        }
    
        // Handle paths
        if (blobPath && blobPath !== project.blobPath) {
            updatedConfig.blobPath = blobPath;
            changes.push('Updated blob path');
        }
        if (dbPath && dbPath !== project.dbPath) {
            updatedConfig.dbPath = dbPath;
            changes.push('Updated database path');
        }
        if (logPath && logPath !== project.logPath) {
            updatedConfig.logPath = logPath;
            changes.push('Updated log path');
        }
    
        // Handle default setting
        if (makeDefault) {
            updatedConfig.isDefault = true;
            // Remove default from other projects
            this.dynamicConfigurations.forEach(c => {
                if (c.name !== updatedConfig.name) {
                    c.isDefault = false;
                }
            });
            // Set as last used project for getCurrentProject() resolution
            this.setLastUsedProject(updatedConfig.name);
            changes.push('Set as default project');
        }
    
        // If project was Unknown and now has credentials, mark as configured
        if (project.isUnknown && (apiKey || connectionString)) {
            updatedConfig.isUnknown = false;
            updatedConfig.needsConfiguration = false;
            delete updatedConfig.configurationHint;
            if (apiKey) {
                updatedConfig.projectType = 'dxp-paas';
                changes.push('Upgraded from Unknown to DXP PaaS');
            } else if (connectionString) {
                updatedConfig.projectType = 'self-hosted';
                changes.push('Upgraded from Unknown to Self-Hosted');
            }
        }
    
        if (changes.length === 0) {
            return ResponseBuilder.formatResponse({
                success: true,
                message: 'No changes to apply',
                details: `Project '${project.name}' is already up to date`
            });
        }
    
        // Update timestamps
        updatedConfig.configSource = 'dynamic';
        updatedConfig.lastUpdated = new Date().toISOString();
    
        // Save the configuration
        this.addConfiguration(updatedConfig);
    
        // DXP-148 FIX: When credentials are provided inline, treat as implicit makeDefault
        // This ensures the most recently added/updated project becomes the default
        // Critical for multi-project n8n workflows where projects are added dynamically
        if ((apiKey && apiSecret) || connectionString) {
            this.setLastUsedProject(updatedConfig.name);
            OutputLogger.debug(`[DXP-148] Set '${updatedConfig.name}' as last used project (inline credentials provided)`);
        }
    
        // Build response
        const sections: string[] = [];
        sections.push(`✅ **Project Updated Successfully**`);
        sections.push('');
        sections.push(`**${updatedConfig.name}**`);
        sections.push(`Type: ${updatedConfig.projectType === 'self-hosted' ? 'Self-Hosted' : 'DXP PaaS'}`);
        sections.push('');
        sections.push('**Changes Applied:**');
        changes.forEach(change => sections.push(`• ${change}`));
    
        if (updatedConfig.blobPath || updatedConfig.dbPath || updatedConfig.logPath) {
            sections.push('');
            sections.push('**Download Paths:**');
            if (updatedConfig.blobPath) sections.push(`• Blobs: ${updatedConfig.blobPath}`);
            if (updatedConfig.dbPath) sections.push(`• Database: ${updatedConfig.dbPath}`);
            if (updatedConfig.logPath) sections.push(`• Logs: ${updatedConfig.logPath}`);
        }
    
        return ResponseBuilder.success(sections.join('\n'));
    }
  • Type definition for input parameters to the update_project tool handler.
    interface UpdateProjectArgs {
        projectName?: string;
        projectId?: string;
        renameTo?: string;
        apiKey?: string;
        apiSecret?: string;
        connectionString?: string;
        blobPath?: string;
        dbPath?: string;
        logPath?: string;
        makeDefault?: boolean;
    }
  • Tool availability registration in the central matrix used for hosting-type based access control.
    'update_project': {
        hostingTypes: ['dxp-paas', 'dxp-saas', 'self-hosted', 'unknown'],
        category: 'Project Management',
        description: 'Update project configuration: rename, credentials, paths, or settings'
    },
  • Key helper method that parses environment variables and dynamic configs into ProjectConfig objects, used by update_project for finding and updating 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;
  • Helper for adding or updating dynamic (in-memory) project configurations, called by update_project to persist changes.
    static addConfiguration(configInfo: ProjectConfig): ProjectConfig {
        // Check if configuration already exists by ID or name
        // Special handling: If upgrading from Unknown, match by name only
        const existingIndex = this.dynamicConfigurations.findIndex(c => {
            // Match by name (case-insensitive)
            const nameMatch = c.name.toLowerCase() === configInfo.name.toLowerCase();
    
            // If names match and one is Unknown being upgraded, that's a match
            if (nameMatch && (c.isUnknown || configInfo.wasUnknown)) {
                return true;
            }
    
            // Otherwise match by projectId or name
            return c.projectId === configInfo.projectId || c.name === configInfo.name;
        });
    
        if (existingIndex >= 0) {
            // Update existing configuration
            this.dynamicConfigurations[existingIndex] = {
                ...this.dynamicConfigurations[existingIndex],
                ...configInfo,
                lastUsed: new Date().toISOString()
            };
        } else {
            // Add new configuration
            this.dynamicConfigurations.push({
                ...configInfo,
                addedAt: new Date().toISOString(),
                lastUsed: new Date().toISOString()
            });
        }
    
        return configInfo;
    }
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden of behavioral disclosure. It does well by specifying the operation is 'INSTANT: <1s', that changes 'persist for session', and includes important warnings about credential validity and downstream impacts. It also mentions the return value ('Returns updated project config'). However, it doesn't address permissions, error handling, or whether changes are reversible.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is appropriately sized and front-loaded with the core purpose. Each sentence adds value: timing information, what can be modified, persistence, warnings, requirements, return value, and testing recommendation. There's minimal redundancy, though the structure could be slightly more organized.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a mutation tool with 10 parameters, no annotations, and no output schema, the description provides good behavioral context but insufficient parameter documentation. It covers timing, persistence, warnings, and testing recommendations, which helps compensate for missing annotations. However, the parameter guidance is misleading and incomplete given the low schema coverage, leaving significant gaps in understanding how to use the tool effectively.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is only 10% (only 'makeDefault' has a description), so the description must compensate. While it mentions 'Required: projectName, updates (object with fields to change)', this is misleading since the schema shows 0 required parameters and no 'updates' parameter exists. The description lists some parameter categories (credentials, name, environment settings) but doesn't map them to the 10 specific parameters in the schema, leaving most undocumented.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the verb 'update' and resource 'project configuration settings', specifying what fields can be modified (credentials, name, environment settings). It distinguishes from sibling 'get_project' which presumably reads rather than modifies. However, it doesn't explicitly differentiate from 'switch_project' or other project-related tools.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides clear context for when to use ('modifies stored credentials, project name, or environment settings') and includes a caution about invalid credentials breaking subsequent operations. It also suggests testing with 'test_connection()' after updating. However, it doesn't explicitly state when NOT to use this tool or provide alternatives for specific scenarios.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

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