UNPKG

salesforce-data-dictionary

Version:

MCP server for Salesforce Data Dictionary Generation

223 lines 11 kB
import { SalesforceManager } from "./salesforceManager.js"; import * as XLSX from "xlsx"; export class ToolManager { salesforceManager; constructor() { this.salesforceManager = new SalesforceManager(); } getAvailableTools() { return [ { name: "Describe Salesforce Object", description: "Describe a Salesforce object and return its field information in CSV format", inputSchema: { type: "object", properties: { objectName: { type: "string", description: "Name of the Salesforce object to describe (e.g., Account, Contact, CustomObject__c)" }, outputFile: { type: "string", description: "Optional filename to save the CSV output (e.g., 'account_fields.csv')" } }, required: ["objectName"] } }, { name: "List Salesforce Objects", description: "List all available Salesforce objects", inputSchema: { type: "object", properties: { searchTerm: { type: "string", description: "Optional search term to filter objects" } } } }, { name: "Find Similar Objects", description: "Find Salesforce objects with similar names", inputSchema: { type: "object", properties: { searchTerm: { type: "string", description: "Search term to find similar object names" } }, required: ["searchTerm"] } }, { name: "Create Data Dictionary", description: "Create a data dictionary from one or more Salesforce objects and export as Excel (one tab per object)", inputSchema: { type: "object", properties: { objects: { type: "string", description: "Comma-separated list of Salesforce objects (e.g., 'Account, Contact, CustomObject__c'). Use 'ALL', 'all objects', 'whole org', or '*' to include every object." }, outputFile: { type: "string", description: "Filename for the Excel output (e.g., 'data_dictionary.xlsx')" } }, required: ["objects", "outputFile"] } } ]; } async callTool(name, args) { switch (name) { case "Describe Salesforce Object": return await this.describeSalesforceObject(args); case "List Salesforce Objects": return await this.listSalesforceObjects(args); case "Find Similar Objects": return await this.findSimilarObjects(args); case "Create Data Dictionary": return await this.createDataDictionaryFromSalesforce(args); default: throw new Error(`Unknown tool: ${name}`); } } async describeSalesforceObject(args) { const { objectName, outputFile } = args; try { const allObjects = await this.salesforceManager.listAllObjects(); const exactMatch = allObjects.find(obj => obj.toLowerCase() === objectName.toLowerCase()); if (!exactMatch) { const similarObjects = await this.salesforceManager.findSimilarObjects(objectName); if (similarObjects.length === 0) { return { content: [{ type: "text", text: `Object '${objectName}' not found. No similar objects found either.` }] }; } return { content: [{ type: "text", text: `Object '${objectName}' not found. Did you mean one of these?\n${similarObjects.map(obj => `- ${obj}`).join('\n')}` }] }; } const object = await this.salesforceManager.describeObject(exactMatch); const csvContent = this.salesforceManager.generateCSV(object); const summary = this.salesforceManager.generateObjectSummary(object); if (outputFile) { this.salesforceManager.saveCSVToFile(csvContent, outputFile); } return { content: [{ type: "text", text: `${summary}\n\nCSV Output:\n${csvContent}${outputFile ? `\n\nCSV saved to: ${outputFile}` : ''}` }] }; } catch (error) { return { content: [{ type: "text", text: `Error describing Salesforce object '${objectName}': ${error instanceof Error ? error.message : 'Unknown error'}` }] }; } } async listSalesforceObjects(args) { try { const { searchTerm } = args; const allObjects = await this.salesforceManager.listAllObjects(); let filteredObjects = allObjects; if (searchTerm) { const searchLower = searchTerm.toLowerCase(); filteredObjects = allObjects.filter(obj => obj.toLowerCase().includes(searchLower)); } if (filteredObjects.length === 0) { return { content: [{ type: "text", text: searchTerm ? `No Salesforce objects found matching '${searchTerm}'` : "No Salesforce objects found" }] }; } return { content: [{ type: "text", text: `Found ${filteredObjects.length} Salesforce objects${searchTerm ? ` matching '${searchTerm}'` : ''}:\n\n${filteredObjects.map(obj => `- ${obj}`).join('\n')}` }] }; } catch (error) { return { content: [{ type: "text", text: `Error listing Salesforce objects: ${error instanceof Error ? error.message : 'Unknown error'}` }] }; } } async findSimilarObjects(args) { const { searchTerm } = args; try { const similarObjects = await this.salesforceManager.findSimilarObjects(searchTerm); if (similarObjects.length === 0) { return { content: [{ type: "text", text: `No Salesforce objects found similar to '${searchTerm}'` }] }; } return { content: [{ type: "text", text: `Found ${similarObjects.length} Salesforce objects similar to '${searchTerm}':\n\n${similarObjects.map(obj => `- ${obj}`).join('\n')}` }] }; } catch (error) { return { content: [{ type: "text", text: `Error finding similar objects: ${error instanceof Error ? error.message : 'Unknown error'}` }] }; } } async createDataDictionaryFromSalesforce(args) { const { objects, outputFile } = args; try { const rawTokens = (objects || '') .split(',') .map((s) => s.trim()) .filter((s) => s.length > 0); if (rawTokens.length === 0) { return { content: [{ type: "text", text: "Please provide at least one Salesforce object name." }] }; } const allObjects = await this.salesforceManager.listAllObjects(); const wantsAllRegex = /^(all|all objects|everything|whole org|entire org|\*)$/i; const wantsAll = rawTokens.some((t) => wantsAllRegex.test(t)); let resolvedNames = []; const notFound = []; if (wantsAll) { resolvedNames = [...allObjects]; } else { for (const name of rawTokens) { const match = allObjects.find(o => o.toLowerCase() === name.toLowerCase()); if (match) { resolvedNames.push(match); } else { const similar = await this.salesforceManager.findSimilarObjects(name); if (similar.length > 0) { resolvedNames.push(similar[0]); } else { notFound.push(name); } } } } if (resolvedNames.length === 0) { return { content: [{ type: "text", text: `No valid Salesforce objects found. Missing: ${notFound.join(', ')}` }] }; } const workbook = XLSX.utils.book_new(); const processed = []; // Safety: avoid massive workbooks by limiting sheet name collisions and catch describe failures per object for (const objName of resolvedNames) { let desc; try { desc = await this.salesforceManager.describeObject(objName); } catch (e) { processed.push(`${objName} -> ERROR: ${e.message}`); continue; } const rows = desc.fields.map(f => ({ "Field Name": f.name, "Type": f.type, "Label": f.label, "Description": f.description || '', "Required": f.required ? 'Yes' : 'No', "Unique": f.unique ? 'Yes' : 'No', "Length": f.length ?? '', "Precision": f.precision ?? '', "Scale": f.scale ?? '', "Default Value": f.defaultValue ?? '', "Picklist Values": f.picklistValues ? f.picklistValues.map(p => `${p.value} (${p.label})`).join('; ') : '', "Reference To": f.referenceTo ? f.referenceTo.join(', ') : '', "Relationship Name": f.relationshipName || '' })); const sheet = XLSX.utils.json_to_sheet(rows); const tabName = desc.label?.toString().slice(0, 31) || objName.slice(0, 31); XLSX.utils.book_append_sheet(workbook, sheet, tabName); processed.push(`${objName} -> ${tabName} (${rows.length} fields)`); } XLSX.writeFile(workbook, outputFile); const extra = notFound.length > 0 ? `\nNot found: ${notFound.join(', ')}` : ''; return { content: [{ type: "text", text: `Excel created: ${outputFile}\nSheets: ${processed.join('\n')}${extra}` }] }; } catch (error) { return { content: [{ type: "text", text: `Error creating Excel data dictionary: ${error instanceof Error ? error.message : 'Unknown error'}` }] }; } } } //# sourceMappingURL=toolManager.js.map