salesforce-data-dictionary
Version:
MCP server for Salesforce Data Dictionary Generation
223 lines • 11 kB
JavaScript
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