Salesforce MCP Server
by SurajAdsul
- src
- tools
import { Tool } from "@modelcontextprotocol/sdk/types.js";
import { DMLResult } from "../types/salesforce";
export const DML_RECORDS: Tool = {
name: "salesforce_dml_records",
description: `Perform data manipulation operations on Salesforce records:
- insert: Create new records
- update: Modify existing records (requires Id)
- delete: Remove records (requires Id)
- upsert: Insert or update based on external ID field
Examples: Insert new Accounts, Update Case status, Delete old records, Upsert based on custom external ID`,
inputSchema: {
type: "object",
properties: {
operation: {
type: "string",
enum: ["insert", "update", "delete", "upsert"],
description: "Type of DML operation to perform"
},
objectName: {
type: "string",
description: "API name of the object"
},
records: {
type: "array",
items: { type: "object" },
description: "Array of records to process"
},
externalIdField: {
type: "string",
description: "External ID field name for upsert operations",
optional: true
}
},
required: ["operation", "objectName", "records"]
}
};
export interface DMLArgs {
operation: 'insert' | 'update' | 'delete' | 'upsert';
objectName: string;
records: Record<string, any>[];
externalIdField?: string;
}
export async function handleDMLRecords(conn: any, args: DMLArgs) {
const { operation, objectName, records, externalIdField } = args;
let result: DMLResult | DMLResult[];
switch (operation) {
case 'insert':
result = await conn.sobject(objectName).create(records);
break;
case 'update':
result = await conn.sobject(objectName).update(records);
break;
case 'delete':
result = await conn.sobject(objectName).destroy(records.map(r => r.Id));
break;
case 'upsert':
if (!externalIdField) {
throw new Error('externalIdField is required for upsert operations');
}
result = await conn.sobject(objectName).upsert(records, externalIdField);
break;
default:
throw new Error(`Unsupported operation: ${operation}`);
}
// Format DML results
const results = Array.isArray(result) ? result : [result];
const successCount = results.filter(r => r.success).length;
const failureCount = results.length - successCount;
let responseText = `${operation.toUpperCase()} operation completed.\n`;
responseText += `Processed ${results.length} records:\n`;
responseText += `- Successful: ${successCount}\n`;
responseText += `- Failed: ${failureCount}\n\n`;
if (failureCount > 0) {
responseText += 'Errors:\n';
results.forEach((r: DMLResult, idx: number) => {
if (!r.success && r.errors) {
responseText += `Record ${idx + 1}:\n`;
if (Array.isArray(r.errors)) {
r.errors.forEach((error) => {
responseText += ` - ${error.message}`;
if (error.statusCode) {
responseText += ` [${error.statusCode}]`;
}
if (error.fields && error.fields.length > 0) {
responseText += `\n Fields: ${error.fields.join(', ')}`;
}
responseText += '\n';
});
} else {
// Single error object
const error = r.errors;
responseText += ` - ${error.message}`;
if (error.statusCode) {
responseText += ` [${error.statusCode}]`;
}
if (error.fields) {
const fields = Array.isArray(error.fields) ? error.fields.join(', ') : error.fields;
responseText += `\n Fields: ${fields}`;
}
responseText += '\n';
}
}
});
}
return {
content: [{
type: "text",
text: responseText
}],
isError: false,
};
}