import { BaseTool } from '../../registry/base-tool.js';
import { getSessionCredentialsSchema } from '../../utils/tool-schema.js';
export class UpdateCaseTool extends BaseTool {
/**
* Get the category this tool belongs to
*/
static getCategory() {
return 'cases';
}
/**
* Get tool definition for MCP protocol
*/
static getDefinition() {
return {
name: 'update_case',
description: 'Update a Pega case by directly modifying case properties. V1 EXCLUSIVE - only available in Traditional DX API. V2 uses perform_case_action instead. If eTag is not provided, automatically fetches the latest eTag from the case for seamless operation. Performs case-wide or stage-wide local action (defaults to pyUpdateCaseDetails if actionID not specified).',
inputSchema: {
type: 'object',
properties: {
caseID: {
type: 'string',
description: 'Case ID. Example: "MYORG-APP-WORK C-1001". Complete identifier including spaces.'
},
content: {
type: 'object',
description: 'Map of case properties to update. Only valid case properties can be set. Example: {"Status": "Approved", "Priority": "High"}. Empty object is valid for action-only updates.'
},
actionID: {
type: 'string',
description: 'Action ID to perform. Default: pyUpdateCaseDetails. Example: "ApproveCase"'
},
eTag: {
type: 'string',
description: 'eTag for optimistic locking. If not provided, automatically fetches latest eTag. Format: "20251016T120000.000 GMT"'
},
pageInstructions: {
type: 'array',
items: {
type: 'object',
properties: {
instruction: {
type: 'string',
enum: ['UPDATE', 'REPLACE', 'DELETE', 'APPEND', 'INSERT', 'MOVE'],
description: 'Page instruction type. UPDATE (add fields to page), REPLACE (replace entire page), DELETE (remove page), APPEND (add item to page list), INSERT (insert item in page list), MOVE (reorder page list items)'
},
target: {
type: 'string',
description: 'Target embedded page name'
},
content: {
type: 'object',
description: 'Content to set on the embedded page (required for UPDATE and REPLACE)'
}
},
required: ['instruction', 'target'],
description: 'Page operation for embedded pages. Use REPLACE instruction to set embedded page references with full object including pzInsKey. Example: {"instruction": "REPLACE", "target": "PageName", "content": {"Property": "value", "pyID": "ID-123", "pzInsKey": "CLASS-NAME ID-123"}}'
},
description: 'Optional list of page-related operations for embedded pages, page lists, or page groups. Required for setting embedded page references.'
},
attachments: {
type: 'array',
description: 'Optional list of attachments to add to the case during update.',
items: {
type: 'object'
}
},
sessionCredentials: getSessionCredentialsSchema()
},
required: ['caseID', 'content']
}
};
}
/**
* Execute the update case operation
*/
async execute(params) {
const { caseID, content, actionID, eTag, pageInstructions, attachments } = params;
let sessionInfo = null;
try {
// Initialize session configuration if provided
sessionInfo = this.initializeSessionConfig(params);
// Check if V1 API
if (this.pegaClient.getApiVersion() !== 'v1') {
return {
error: 'update_case is only available in Traditional DX API (V1). For V2, use perform_case_action tool instead with actionID "pyUpdateCaseDetails".'
};
}
// Validate required parameters
const requiredValidation = this.validateRequiredParams(params, ['caseID', 'content']);
if (requiredValidation) {
return requiredValidation;
}
// Execute with standardized error handling
return await this.executeWithErrorHandling(
`Update Case: ${caseID}`,
async () => {
const options = { content };
if (actionID) options.actionID = actionID;
if (eTag) options.eTag = eTag;
if (pageInstructions) options.pageInstructions = pageInstructions;
if (attachments) options.attachments = attachments;
return await this.pegaClient.updateCase(caseID.trim(), options);
},
{ caseID, actionID, eTag, hasContent: !!content, sessionInfo }
);
} catch (error) {
return {
content: [{
type: 'text',
text: `## Error: Update Case
**Unexpected Error**: ${error.message}
${sessionInfo ? `**Session**: ${sessionInfo.sessionId} (${sessionInfo.authMode} mode)\n` : ''}*Error occurred at: ${new Date().toISOString()}*`
}]
};
}
}
/**
* Override formatSuccessResponse for update case specific formatting
*/
formatSuccessResponse(operation, data, options = {}) {
const { caseID, actionID, eTag, hasContent, sessionInfo } = options;
let response = `## ${operation}\n\n`;
response += `*Operation completed at: ${new Date().toISOString()}*\n\n`;
// Session Information (if applicable)
if (sessionInfo) {
response += `### Session Information\n`;
response += `- **Session ID**: ${sessionInfo.sessionId}\n`;
response += `- **Authentication Mode**: ${sessionInfo.authMode.toUpperCase()}\n`;
response += `- **Configuration Source**: ${sessionInfo.configSource}\n\n`;
}
// Display update summary
response += '### Update Summary\n';
response += `- **Case ID**: ${caseID}\n`;
response += `- **Action**: ${actionID || 'pyUpdateCaseDetails (default)'}\n`;
response += `- **HTTP Status**: ${data.metadata?.statusCode || 'N/A'}\n`;
response += `- **API Version**: ${data.metadata?.apiVersion || 'v1'}\n`;
if (data.metadata?.autoFetchedETag) {
response += '\n### ๐ Automatic eTag Management\n';
response += '- โ
Latest eTag automatically fetched before update\n';
response += '- No manual GET operation needed\n';
response += '- Optimistic locking ensured\n';
} else if (eTag) {
response += '\n### ๐ Manual eTag Provided\n';
response += `- eTag used: \`${eTag}\`\n`;
response += '- Manual eTag management mode\n';
}
// Display new eTag for future operations
if (data.eTag) {
response += '\n### ๐ New eTag\n';
response += `- **eTag**: \`${data.eTag}\`\n`;
response += '- Use this eTag for subsequent operations\n';
response += '- Case state has been updated\n';
}
if (hasContent) {
response += '\n### ๐ Content Update\n';
response += '- โ
Case properties updated\n';
} else {
response += '\n### ๐ Action-Only Update\n';
response += '- No content properties changed\n';
response += '- Action performed on case\n';
}
response += '\n### โ
Operation Status\n';
response += `- ${data.data?.message || 'Case updated successfully'}\n`;
response += '- Case committed to database\n';
response += '- Use get_case to view updated case details\n';
response += '\n### ๐ V1 vs V2\n';
response += '- **V1**: Direct case update with PUT /cases/{ID}\n';
response += '- **V2**: Use perform_case_action with pyUpdateCaseDetails instead\n';
response += '- **Auto-fetch**: Available in both V1 and V2 โ
\n';
return response;
}
/**
* Override formatErrorResponse for update case specific error context
*/
formatErrorResponse(operation, error, options = {}) {
const { caseID, actionID, eTag } = options;
let response = `## โ ${operation} Failed\n\n`;
response += `*Error occurred at: ${new Date().toISOString()}*\n\n`;
response += '### Operation Context\n';
response += `- **Case ID**: ${caseID}\n`;
response += `- **Action**: ${actionID || 'pyUpdateCaseDetails (default)'}\n`;
response += `- **eTag Used**: ${eTag || '(auto-fetch)'}\n\n`;
response += `### Error Details\n`;
response += `- **Type**: ${error.type}\n`;
response += `- **Message**: ${error.message}\n`;
response += `- **Details**: ${error.details}\n`;
if (error.status) {
response += `- **HTTP Status**: ${error.status} ${error.statusText || ''}\n`;
}
// Provide specific guidance based on error type
response += '\n### Troubleshooting Guidance\n';
switch (error.type) {
case 'AUTO_FETCH_FAILED':
response += '**Auto-Fetch Failed**:\n';
response += '- Could not retrieve case to obtain eTag\n';
response += '- **Solution**: Verify case ID is correct and case exists\n';
response += '- Or provide eTag manually if you already have it\n';
break;
case 'ETAG_MISSING':
response += '**eTag Missing**:\n';
response += '- Case retrieved but no eTag in response\n';
response += '- **Solution**: This may indicate a server configuration issue\n';
response += '- Contact Pega administrator\n';
break;
case 'HTTP_ERROR':
if (error.status === 412) {
response += '**Precondition Failed (412)**:\n';
response += '- eTag is stale - case was modified by another user\n';
response += '- **Solution**: Retry operation (eTag will auto-fetch latest)\n';
} else {
response += '**HTTP Error**:\n';
response += '- Unexpected HTTP error occurred\n';
response += '- **Solution**: Check error details and retry\n';
}
break;
case 'NOT_FOUND':
response += '**Case Not Found (404)**:\n';
response += '- Case ID could not be found\n';
response += '- **Solution**: Verify case ID format and spelling\n';
response += '- Use get_case tool to confirm case exists\n';
break;
case 'FORBIDDEN':
response += '**Access Denied (403)**:\n';
response += '- User lacks permission to update this case\n';
response += '- **Solution**: Contact administrator to verify access rights\n';
break;
default:
response += '**General Error**:\n';
response += '- Review error details above\n';
response += '- **Solution**: Verify case ID and parameters\n';
break;
}
return response;
}
}