Skip to main content
Glama
tsmztech

Salesforce MCP Server

salesforce_read_apex_trigger

Retrieve Apex trigger code and metadata from Salesforce to analyze automation logic, review business rules, or troubleshoot workflow issues.

Instructions

Read Apex triggers from Salesforce.

Examples:

  1. Read a specific Apex trigger by name: { "triggerName": "AccountTrigger" }

  2. List all Apex triggers with an optional name pattern: { "namePattern": "Account" }

  3. Get metadata about Apex triggers: { "includeMetadata": true, "namePattern": "Contact" }

  4. Use wildcards in name patterns: { "namePattern": "Account*" }

Notes:

  • When triggerName is provided, the full body of that specific trigger is returned

  • When namePattern is provided, all matching trigger names are returned (without body)

  • Use includeMetadata to get additional information like API version, object type, and last modified date

  • If neither triggerName nor namePattern is provided, all Apex trigger names will be listed

  • Wildcards are supported in namePattern: * (matches any characters) and ? (matches a single character)

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
triggerNameNoName of a specific Apex trigger to read
namePatternNoPattern to match Apex trigger names (supports wildcards * and ?)
includeMetadataNoWhether to include metadata about the Apex triggers

Implementation Reference

  • Core handler function that executes the tool logic: queries Salesforce ApexTrigger object for specific trigger body or list matching pattern, handles metadata, formats markdown responses with code blocks or tables.
    export async function handleReadApexTrigger(conn: any, args: ReadApexTriggerArgs) {
      try {
        // If a specific trigger name is provided, get the full trigger body
        if (args.triggerName) {
          console.error(`Reading Apex trigger: ${args.triggerName}`);
          
          // Query the ApexTrigger object to get the trigger body
          const result = await conn.query(`
            SELECT Id, Name, Body, ApiVersion, TableEnumOrId, Status, 
                   IsValid, LastModifiedDate, LastModifiedById
            FROM ApexTrigger 
            WHERE Name = '${args.triggerName}'
          `);
          
          if (result.records.length === 0) {
            return {
              content: [{ 
                type: "text", 
                text: `No Apex trigger found with name: ${args.triggerName}` 
              }],
              isError: true,
            };
          }
          
          const apexTrigger = result.records[0];
          
          // Format the response with the trigger body and metadata
          return {
            content: [
              { 
                type: "text", 
                text: `# Apex Trigger: ${apexTrigger.Name}\n\n` +
                      (args.includeMetadata ? 
                        `**API Version:** ${apexTrigger.ApiVersion}\n` +
                        `**Object:** ${apexTrigger.TableEnumOrId}\n` +
                        `**Status:** ${apexTrigger.Status}\n` +
                        `**Valid:** ${apexTrigger.IsValid ? 'Yes' : 'No'}\n` +
                        `**Last Modified:** ${new Date(apexTrigger.LastModifiedDate).toLocaleString()}\n\n` : '') +
                      "```apex\n" + apexTrigger.Body + "\n```"
              }
            ]
          };
        } 
        // Otherwise, list triggers matching the pattern
        else {
          console.error(`Listing Apex triggers${args.namePattern ? ` matching: ${args.namePattern}` : ''}`);
          
          // Build the query
          let query = `
            SELECT Id, Name${args.includeMetadata ? ', ApiVersion, TableEnumOrId, Status, IsValid, LastModifiedDate' : ''}
            FROM ApexTrigger
          `;
          
          // Add name pattern filter if provided
          if (args.namePattern) {
            const likePattern = wildcardToLikePattern(args.namePattern);
            query += ` WHERE Name LIKE '${likePattern}'`;
          }
          
          // Order by name
          query += ` ORDER BY Name`;
          
          const result = await conn.query(query);
          
          if (result.records.length === 0) {
            return {
              content: [{ 
                type: "text", 
                text: `No Apex triggers found${args.namePattern ? ` matching: ${args.namePattern}` : ''}` 
              }]
            };
          }
          
          // Format the response as a list of triggers
          let responseText = `# Found ${result.records.length} Apex Triggers\n\n`;
          
          if (args.includeMetadata) {
            // Table format with metadata
            responseText += "| Name | API Version | Object | Status | Valid | Last Modified |\n";
            responseText += "|------|------------|--------|--------|-------|---------------|\n";
            
            for (const trigger of result.records) {
              responseText += `| ${trigger.Name} | ${trigger.ApiVersion} | ${trigger.TableEnumOrId} | ${trigger.Status} | ${trigger.IsValid ? 'Yes' : 'No'} | ${new Date(trigger.LastModifiedDate).toLocaleString()} |\n`;
            }
          } else {
            // Simple list format
            for (const trigger of result.records) {
              responseText += `- ${trigger.Name}\n`;
            }
          }
          
          return {
            content: [{ type: "text", text: responseText }]
          };
        }
      } catch (error) {
        console.error('Error reading Apex triggers:', error);
        return {
          content: [{ 
            type: "text", 
            text: `Error reading Apex triggers: ${error instanceof Error ? error.message : String(error)}` 
          }],
          isError: true,
        };
      }
    }
  • Tool schema definition including name, detailed description with examples, and inputSchema for parameters: triggerName, namePattern, includeMetadata.
    export const READ_APEX_TRIGGER: Tool = {
      name: "salesforce_read_apex_trigger",
      description: `Read Apex triggers from Salesforce.
      
    Examples:
    1. Read a specific Apex trigger by name:
       {
         "triggerName": "AccountTrigger"
       }
    
    2. List all Apex triggers with an optional name pattern:
       {
         "namePattern": "Account"
       }
    
    3. Get metadata about Apex triggers:
       {
         "includeMetadata": true,
         "namePattern": "Contact"
       }
    
    4. Use wildcards in name patterns:
       {
         "namePattern": "Account*"
       }
    
    Notes:
    - When triggerName is provided, the full body of that specific trigger is returned
    - When namePattern is provided, all matching trigger names are returned (without body)
    - Use includeMetadata to get additional information like API version, object type, and last modified date
    - If neither triggerName nor namePattern is provided, all Apex trigger names will be listed
    - Wildcards are supported in namePattern: * (matches any characters) and ? (matches a single character)`,
      inputSchema: {
        type: "object",
        properties: {
          triggerName: {
            type: "string",
            description: "Name of a specific Apex trigger to read"
          },
          namePattern: {
            type: "string",
            description: "Pattern to match Apex trigger names (supports wildcards * and ?)"
          },
          includeMetadata: {
            type: "boolean",
            description: "Whether to include metadata about the Apex triggers"
          }
        }
      }
    };
  • src/index.ts:257-268 (registration)
    Server request handler registration: switch case that validates arguments and delegates to handleReadApexTrigger.
    case "salesforce_read_apex_trigger": {
      const triggerArgs = args as Record<string, unknown>;
      
      // Type check and conversion
      const validatedArgs: ReadApexTriggerArgs = {
        triggerName: triggerArgs.triggerName as string | undefined,
        namePattern: triggerArgs.namePattern as string | undefined,
        includeMetadata: triggerArgs.includeMetadata as boolean | undefined
      };
    
      return await handleReadApexTrigger(conn, validatedArgs);
    }
  • src/index.ts:45-63 (registration)
    Registers the READ_APEX_TRIGGER tool in the server's listTools response.
    server.setRequestHandler(ListToolsRequestSchema, async () => ({
      tools: [
        SEARCH_OBJECTS, 
        DESCRIBE_OBJECT, 
        QUERY_RECORDS, 
        AGGREGATE_QUERY,
        DML_RECORDS,
        MANAGE_OBJECT,
        MANAGE_FIELD,
        MANAGE_FIELD_PERMISSIONS,
        SEARCH_ALL,
        READ_APEX,
        WRITE_APEX,
        READ_APEX_TRIGGER,
        WRITE_APEX_TRIGGER,
        EXECUTE_ANONYMOUS,
        MANAGE_DEBUG_LOGS
      ],
    }));
  • Helper function to convert wildcard patterns (*, ?) to SQL LIKE patterns for querying trigger names.
    function wildcardToLikePattern(pattern: string): string {
      if (!pattern.includes('*') && !pattern.includes('?')) {
        // If no wildcards, wrap with % for substring match
        return `%${pattern}%`;
      }
      
      // Replace * with % and ? with _ for SQL LIKE
      let likePattern = pattern.replace(/\*/g, '%').replace(/\?/g, '_');
      
      return likePattern;
    }

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/tsmztech/mcp-server-salesforce'

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