Skip to main content
Glama
simonl77
by simonl77

salesforce_read_apex

Read Apex classes from Salesforce by name or pattern, retrieve class bodies, list all classes, or get metadata including API version and last modified date.

Instructions

Read Apex classes from Salesforce.

Examples:

  1. Read a specific Apex class by name: { "className": "AccountController" }

  2. List all Apex classes with an optional name pattern: { "namePattern": "Controller" }

  3. Get metadata about Apex classes: { "includeMetadata": true, "namePattern": "Trigger" }

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

Notes:

  • When className is provided, the full body of that specific class is returned

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

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

  • If neither className nor namePattern is provided, all Apex class names will be listed

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

Input Schema

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

Implementation Reference

  • Main handler function that executes the tool logic: queries Salesforce ApexClass for specific class body or lists matching classes with optional metadata, formats response.
    export async function handleReadApex(conn: any, args: ReadApexArgs) { try { // If a specific class name is provided, get the full class body if (args.className) { console.error(`Reading Apex class: ${args.className}`); // Query the ApexClass object to get the class body const result = await conn.query(` SELECT Id, Name, Body, ApiVersion, LengthWithoutComments, Status, IsValid, LastModifiedDate, LastModifiedById FROM ApexClass WHERE Name = '${args.className}' `); if (result.records.length === 0) { return { content: [{ type: "text", text: `No Apex class found with name: ${args.className}` }], isError: true, }; } const apexClass = result.records[0]; // Format the response with the class body and metadata return { content: [ { type: "text", text: `# Apex Class: ${apexClass.Name}\n\n` + (args.includeMetadata ? `**API Version:** ${apexClass.ApiVersion}\n` + `**Length:** ${apexClass.LengthWithoutComments} characters\n` + `**Status:** ${apexClass.Status}\n` + `**Valid:** ${apexClass.IsValid ? 'Yes' : 'No'}\n` + `**Last Modified:** ${new Date(apexClass.LastModifiedDate).toLocaleString()}\n\n` : '') + "```apex\n" + apexClass.Body + "\n```" } ] }; } // Otherwise, list classes matching the pattern else { console.error(`Listing Apex classes${args.namePattern ? ` matching: ${args.namePattern}` : ''}`); // Build the query let query = ` SELECT Id, Name${args.includeMetadata ? ', ApiVersion, LengthWithoutComments, Status, IsValid, LastModifiedDate' : ''} FROM ApexClass `; // 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 classes found${args.namePattern ? ` matching: ${args.namePattern}` : ''}` }] }; } // Format the response as a list of classes let responseText = `# Found ${result.records.length} Apex Classes\n\n`; if (args.includeMetadata) { // Table format with metadata responseText += "| Name | API Version | Length | Status | Valid | Last Modified |\n"; responseText += "|------|------------|--------|--------|-------|---------------|\n"; for (const cls of result.records) { responseText += `| ${cls.Name} | ${cls.ApiVersion} | ${cls.LengthWithoutComments} | ${cls.Status} | ${cls.IsValid ? 'Yes' : 'No'} | ${new Date(cls.LastModifiedDate).toLocaleString()} |\n`; } } else { // Simple list format for (const cls of result.records) { responseText += `- ${cls.Name}\n`; } } return { content: [{ type: "text", text: responseText }] }; } } catch (error) { console.error('Error reading Apex classes:', error); return { content: [{ type: "text", text: `Error reading Apex classes: ${error instanceof Error ? error.message : String(error)}` }], isError: true, }; } }
  • Tool definition with name, description, and inputSchema for parameters: className (specific class), namePattern (wildcard search), includeMetadata (boolean).
    export const READ_APEX: Tool = { name: "salesforce_read_apex", description: `Read Apex classes from Salesforce. Examples: 1. Read a specific Apex class by name: { "className": "AccountController" } 2. List all Apex classes with an optional name pattern: { "namePattern": "Controller" } 3. Get metadata about Apex classes: { "includeMetadata": true, "namePattern": "Trigger" } 4. Use wildcards in name patterns: { "namePattern": "Account*Cont*" } Notes: - When className is provided, the full body of that specific class is returned - When namePattern is provided, all matching class names are returned (without body) - Use includeMetadata to get additional information like API version, length, and last modified date - If neither className nor namePattern is provided, all Apex class names will be listed - Wildcards are supported in namePattern: * (matches any characters) and ? (matches a single character)`, inputSchema: { type: "object", properties: { className: { type: "string", description: "Name of a specific Apex class to read" }, namePattern: { type: "string", description: "Pattern to match Apex class names (supports wildcards * and ?)" }, includeMetadata: { type: "boolean", description: "Whether to include metadata about the Apex classes" } } } };
  • src/index.ts:45-63 (registration)
    Registers the salesforce_read_apex tool (as READ_APEX) in the MCP server's list of available tools.
    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 ], }));
  • src/index.ts:227-238 (registration)
    Switch case that handles calls to salesforce_read_apex by validating arguments and invoking handleReadApex.
    case "salesforce_read_apex": { const apexArgs = args as Record<string, unknown>; // Type check and conversion const validatedArgs: ReadApexArgs = { className: apexArgs.className as string | undefined, namePattern: apexArgs.namePattern as string | undefined, includeMetadata: apexArgs.includeMetadata as boolean | undefined }; return await handleReadApex(conn, validatedArgs); }
  • Helper function to convert wildcard patterns (*, ?) to SQL LIKE patterns (% , _) used for querying Apex class 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/simonl77/mcp-server-salesforce'

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