Skip to main content
Glama
marco-looy

Pega DX MCP Server

by marco-looy

add_case_attachments

Attach files or URLs to Pega cases at any lifecycle stage using uploaded file IDs or direct links, with atomic operation ensuring all attachments succeed or none are added.

Instructions

Attach files and/or URLs to a Pega case regardless of the context or stage of the case lifecycle. Can attach temporary uploaded files using their IDs (from upload_attachment tool), or add URL/link attachments directly. Supports multiple attachments in a single atomic operation - if any attachment fails, no attachments are added to the case.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
caseIDYesCase ID. Example: "MYORG-APP-WORK C-1001". Complete identifier including spaces."OSIEO3-DOCSAPP-WORK T-561003". a complete case identifier including spaces and special characters.
attachmentsYesArray of attachment objects to add to the case. Can contain file attachments (using temporary attachment IDs from upload_attachment tool) and/or URL attachments. All attachments must be successfully processed or none will be attached (atomic operation).
sessionCredentialsNoOptional session-specific credentials. If not provided, uses environment variables. Supports two authentication modes: (1) OAuth mode - provide baseUrl, clientId, and clientSecret, or (2) Token mode - provide baseUrl and accessToken.

Implementation Reference

  • Main handler function that orchestrates the tool execution: parameter validation, session initialization, API call to pegaClient.addCaseAttachments, and error handling with custom formatted responses.
    async execute(params) {
      const { caseID, attachments } = params;
    
      let sessionInfo = null;
      try {
        sessionInfo = this.initializeSessionConfig(params);
    
        // Basic parameter validation using base class
        const requiredValidation = this.validateRequiredParams(params, ['caseID', 'attachments']);
        if (requiredValidation) {
          return this.createErrorResponse(`Add Attachments to Case: ${caseID || 'UNKNOWN'}`, { message: requiredValidation.error }, { caseID, attachments });
        }
    
        // Additional comprehensive parameter validation for complex logic
        const validationResult = this.validateParameters(caseID, attachments);
        if (!validationResult.valid) {
          return this.createErrorResponse(`Add Attachments to Case: ${caseID}`, { message: validationResult.error }, { caseID, attachments });
        }
    
        // Execute with standardized error handling
        return await this.executeWithErrorHandling(
          `Add Attachments to Case: ${caseID}`,
          async () => await this.pegaClient.addCaseAttachments(caseID, attachments),
          { caseID, attachments, sessionInfo }
        );
      } catch (error) {
        return {
          content: [{
            type: 'text',
            text: `## Error: Add Attachments to Case\n\n**Unexpected Error**: ${error.message}\n\n${sessionInfo ? `**Session**: ${sessionInfo.sessionId} (${sessionInfo.authMode} mode)\n` : ''}*Error occurred at: ${new Date().toISOString()}*`
          }]
        };
      }
    }
  • Static method providing the tool's MCP definition: name, description, and detailed input schema specifying caseID and attachments (array of File or URL objects).
    static getDefinition() {
      return {
        name: 'add_case_attachments',
        description: 'Attach files and/or URLs to a Pega case regardless of the context or stage of the case lifecycle. Can attach temporary uploaded files using their IDs (from upload_attachment tool), or add URL/link attachments directly. Supports multiple attachments in a single atomic operation - if any attachment fails, no attachments are added to the case.',
        inputSchema: {
          type: 'object',
          properties: {
            caseID: {
              type: 'string',
              description: 'Case ID. Example: "MYORG-APP-WORK C-1001". Complete identifier including spaces."OSIEO3-DOCSAPP-WORK T-561003". a complete case identifier including spaces and special characters.'
            },
            attachments: {
              type: 'array',
              description: 'Array of attachment objects to add to the case. Can contain file attachments (using temporary attachment IDs from upload_attachment tool) and/or URL attachments. All attachments must be successfully processed or none will be attached (atomic operation).',
              items: {
                type: 'object',
                properties: {
                  type: {
                    type: 'string',
                    enum: ['File', 'URL'],
                    description: 'Attachment type. "File" for file attachments or "URL" for URL/link attachments.'
                  },
                  category: {
                    type: 'string',
                    enum: ['File', 'URL'],
                    description: 'Attachment category. Must match the type ("File" or "URL").'
                  },
                  ID: {
                    type: 'string',
                    description: 'Temporary attachment ID returned from upload_attachment tool (required for File type). Example: "450b7275-8868-43ca-9827-bcfd9ec1b54b". Note: Temporary attachments expire after 2 hours if not linked to a case.'
                  },
                  url: {
                    type: 'string',
                    description: 'URL/link to attach to the case (required for URL type). Example: "https://www.google.com". a valid URL format.'
                  },
                  name: {
                    type: 'string',
                    description: 'Display name for the URL attachment (required for URL type). Example: "google". This will be shown as the attachment name in the case.'
                  }
                },
                required: ['type', 'category']
              },
              minItems: 1,
              maxItems: 50
            },
            sessionCredentials: getSessionCredentialsSchema()
          },
          required: ['caseID', 'attachments']
        }
      };
    }
  • Comprehensive validation helper for caseID and attachments: checks format, array length (1-50), and delegates to validateAttachmentObject for each item.
    validateParameters(caseID, attachments) {
      // Validate caseID
      if (!caseID || typeof caseID !== 'string' || caseID.trim() === '') {
        return {
          valid: false,
          error: 'Invalid caseID parameter. Case ID must be a non-empty string containing the full case handle.'
        };
      }
    
      // Validate attachments array
      if (!attachments || !Array.isArray(attachments)) {
        return {
          valid: false,
          error: 'Invalid attachments parameter. Attachments must be a non-empty array of attachment objects.'
        };
      }
    
      if (attachments.length === 0) {
        return {
          valid: false,
          error: 'Attachments array cannot be empty. Please provide at least one attachment to add to the case.'
        };
      }
    
      if (attachments.length > 50) {
        return {
          valid: false,
          error: 'Too many attachments provided. Maximum of 50 attachments can be added in a single operation.'
        };
      }
    
      // Validate each attachment object
      for (let i = 0; i < attachments.length; i++) {
        const attachment = attachments[i];
        const attachmentValidation = this.validateAttachmentObject(attachment, i);
        if (!attachmentValidation.valid) {
          return attachmentValidation;
        }
      }
    
      return { valid: true };
    }
  • Validates individual attachment objects: ensures type/category match ('File'/'URL'), required fields (ID for File, url/name for URL), URL format, no extra properties.
    validateAttachmentObject(attachment, index) {
      if (!attachment || typeof attachment !== 'object') {
        return {
          valid: false,
          error: `Invalid attachment at index ${index}. Each attachment must be an object with required properties.`
        };
      }
    
      const { type, category } = attachment;
    
      // Validate required type field
      if (!type || typeof type !== 'string') {
        return {
          valid: false,
          error: `Missing or invalid 'type' field in attachment at index ${index}. Type must be either "File" or "URL".`
        };
      }
    
      // Validate required category field
      if (!category || typeof category !== 'string') {
        return {
          valid: false,
          error: `Missing or invalid 'category' field in attachment at index ${index}. Category must match the type ("File" or "URL").`
        };
      }
    
      // Validate File attachment
      if (type === 'File') {
        if (category !== 'File') {
          return {
            valid: false,
            error: `Invalid category for File attachment at index ${index}. Category must be "File" when type is "File".`
          };
        }
    
        const { ID } = attachment;
        if (!ID || typeof ID !== 'string' || ID.trim() === '') {
          return {
            valid: false,
            error: `Missing or invalid 'ID' field in File attachment at index ${index}. ID must be a non-empty string containing the temporary attachment ID from upload_attachment tool.`
          };
        }
    
        // Check for unexpected properties
        const allowedProps = ['type', 'category', 'ID'];
        const extraProps = Object.keys(attachment).filter(prop => !allowedProps.includes(prop));
        if (extraProps.length > 0) {
          return {
            valid: false,
            error: `Unexpected properties in File attachment at index ${index}: ${extraProps.join(', ')}. File attachments only support: type, category, ID.`
          };
        }
      }
      // Validate URL attachment
      else if (type === 'URL') {
        if (category !== 'URL') {
          return {
            valid: false,
            error: `Invalid category for URL attachment at index ${index}. Category must be "URL" when type is "URL".`
          };
        }
    
        const { url, name } = attachment;
        
        if (!url || typeof url !== 'string' || url.trim() === '') {
          return {
            valid: false,
            error: `Missing or invalid 'url' field in URL attachment at index ${index}. URL must be a non-empty string containing a valid URL.`
          };
        }
    
        // Basic URL format validation
        try {
          new URL(url.trim());
        } catch (urlError) {
          return {
            valid: false,
            error: `Invalid URL format in URL attachment at index ${index}: "${url}". Please provide a valid URL (Example: "https://www.example.com").`
          };
        }
    
        if (!name || typeof name !== 'string' || name.trim() === '') {
          return {
            valid: false,
            error: `Missing or invalid 'name' field in URL attachment at index ${index}. Name must be a non-empty string for the display name of the URL attachment.`
          };
        }
    
        // Check for unexpected properties
        const allowedProps = ['type', 'category', 'url', 'name'];
        const extraProps = Object.keys(attachment).filter(prop => !allowedProps.includes(prop));
        if (extraProps.length > 0) {
          return {
            valid: false,
            error: `Unexpected properties in URL attachment at index ${index}: ${extraProps.join(', ')}. URL attachments only support: type, category, url, name.`
          };
        }
      }
      // Invalid type
      else {
        return {
          valid: false,
          error: `Invalid attachment type "${type}" at index ${index}. Type must be either "File" or "URL".`
        };
      }
    
      return { valid: true };
    }
  • PegaClient wrapper method called by the tool handler to perform the actual API call to add attachments to a case.
    async addCaseAttachments(caseID, attachments) {
      return this.client.addCaseAttachments(caseID, attachments);
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 effectively describes key behavioral traits: atomic operation semantics ('if any attachment fails, no attachments are added'), support for multiple attachments in one call, and the ability to attach both files and URLs. It also hints at prerequisites (temporary file IDs from 'upload_attachment') but doesn't mention authentication requirements, rate limits, or error handling details.

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

Conciseness5/5

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

The description is efficiently structured in three sentences that each add distinct value: purpose statement, attachment types, and atomic operation behavior. It's front-loaded with the core functionality and avoids unnecessary repetition or verbose explanations.

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

Completeness4/5

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

For a mutation tool with no annotations and no output schema, the description provides good coverage of the tool's behavior, atomic semantics, and attachment types. However, it doesn't describe what the tool returns (success/failure indicators, attachment IDs, etc.) or error conditions, which would be important for a tool that modifies case data. The 100% schema coverage helps compensate for some of these gaps.

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

Parameters3/5

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

Schema description coverage is 100%, so the schema already documents all parameters thoroughly. The description adds some context about the 'attachments' parameter (atomic operation, supports multiple attachments) and implies the relationship between 'upload_attachment' and file attachments, but doesn't provide additional semantic meaning beyond what's in the schema. This meets the baseline for high schema coverage.

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

Purpose5/5

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

The description clearly states the specific action ('Attach files and/or URLs'), target resource ('to a Pega case'), and scope ('regardless of the context or stage of the case lifecycle'). It distinguishes itself from sibling tools like 'upload_attachment' (which creates temporary files) and 'update_attachment' (which modifies existing attachments) by focusing on adding attachments to cases.

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 this tool: for attaching files (using IDs from 'upload_attachment') or URLs to cases. It mentions the prerequisite of using 'upload_attachment' for file attachments. However, it doesn't explicitly state when NOT to use it or compare it to alternatives like 'update_attachment' for modifying existing attachments.

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/marco-looy/pega-dx-mcp'

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