@rohithvemulapally/mcp-server-salesforce 0.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +357 -0
  3. package/dist/index.d.ts +2 -0
  4. package/dist/index.js +312 -0
  5. package/dist/tools/aggregateQuery.d.ts +18 -0
  6. package/dist/tools/aggregateQuery.js +250 -0
  7. package/dist/tools/describe.d.ts +9 -0
  8. package/dist/tools/describe.js +33 -0
  9. package/dist/tools/dml.d.ts +15 -0
  10. package/dist/tools/dml.js +105 -0
  11. package/dist/tools/executeAnonymous.d.ts +25 -0
  12. package/dist/tools/executeAnonymous.js +130 -0
  13. package/dist/tools/manageDebugLogs.d.ts +30 -0
  14. package/dist/tools/manageDebugLogs.js +424 -0
  15. package/dist/tools/manageField.d.ts +32 -0
  16. package/dist/tools/manageField.js +349 -0
  17. package/dist/tools/manageFieldPermissions.d.ts +17 -0
  18. package/dist/tools/manageFieldPermissions.js +247 -0
  19. package/dist/tools/manageObject.d.ts +20 -0
  20. package/dist/tools/manageObject.js +138 -0
  21. package/dist/tools/metadata.d.ts +9 -0
  22. package/dist/tools/metadata.js +66 -0
  23. package/dist/tools/query.d.ts +16 -0
  24. package/dist/tools/query.js +114 -0
  25. package/dist/tools/readApex.d.ts +26 -0
  26. package/dist/tools/readApex.js +165 -0
  27. package/dist/tools/readApexTrigger.d.ts +26 -0
  28. package/dist/tools/readApexTrigger.js +165 -0
  29. package/dist/tools/search.d.ts +9 -0
  30. package/dist/tools/search.js +45 -0
  31. package/dist/tools/searchAll.d.ts +29 -0
  32. package/dist/tools/searchAll.js +250 -0
  33. package/dist/tools/writeApex.d.ts +27 -0
  34. package/dist/tools/writeApex.js +154 -0
  35. package/dist/tools/writeApexTrigger.d.ts +28 -0
  36. package/dist/tools/writeApexTrigger.js +178 -0
  37. package/dist/types/connection.d.ts +52 -0
  38. package/dist/types/connection.js +21 -0
  39. package/dist/types/metadata.d.ts +43 -0
  40. package/dist/types/metadata.js +1 -0
  41. package/dist/types/salesforce.d.ts +33 -0
  42. package/dist/types/salesforce.js +1 -0
  43. package/dist/utils/connection.d.ts +7 -0
  44. package/dist/utils/connection.js +172 -0
  45. package/dist/utils/errorHandler.d.ts +15 -0
  46. package/dist/utils/errorHandler.js +23 -0
  47. package/package.json +39 -0
@@ -0,0 +1,349 @@
1
+ export const MANAGE_FIELD = {
2
+ name: "salesforce_manage_field",
3
+ description: `Create new custom fields or modify existing fields on any Salesforce object:
4
+ - Field Types: Text, Number, Date, Lookup, Master-Detail, Picklist etc.
5
+ - Properties: Required, Unique, External ID, Length, Scale etc.
6
+ - Relationships: Create lookups and master-detail relationships
7
+ - Automatically grants Field Level Security to System Administrator (or specified profiles)
8
+ Examples: Add Rating__c picklist to Account, Create Account lookup on Custom Object
9
+ Note: Use grantAccessTo parameter to specify profiles, defaults to System Administrator`,
10
+ inputSchema: {
11
+ type: "object",
12
+ properties: {
13
+ operation: {
14
+ type: "string",
15
+ enum: ["create", "update"],
16
+ description: "Whether to create new field or update existing"
17
+ },
18
+ objectName: {
19
+ type: "string",
20
+ description: "API name of the object to add/modify the field"
21
+ },
22
+ fieldName: {
23
+ type: "string",
24
+ description: "API name for the field (without __c suffix)"
25
+ },
26
+ label: {
27
+ type: "string",
28
+ description: "Label for the field",
29
+ optional: true
30
+ },
31
+ type: {
32
+ type: "string",
33
+ enum: ["Checkbox", "Currency", "Date", "DateTime", "Email", "Number", "Percent",
34
+ "Phone", "Picklist", "MultiselectPicklist", "Text", "TextArea", "LongTextArea",
35
+ "Html", "Url", "Lookup", "MasterDetail"],
36
+ description: "Field type (required for create)",
37
+ optional: true
38
+ },
39
+ required: {
40
+ type: "boolean",
41
+ description: "Whether the field is required",
42
+ optional: true
43
+ },
44
+ unique: {
45
+ type: "boolean",
46
+ description: "Whether the field value must be unique",
47
+ optional: true
48
+ },
49
+ externalId: {
50
+ type: "boolean",
51
+ description: "Whether the field is an external ID",
52
+ optional: true
53
+ },
54
+ length: {
55
+ type: "number",
56
+ description: "Length for text fields",
57
+ optional: true
58
+ },
59
+ precision: {
60
+ type: "number",
61
+ description: "Precision for numeric fields",
62
+ optional: true
63
+ },
64
+ scale: {
65
+ type: "number",
66
+ description: "Scale for numeric fields",
67
+ optional: true
68
+ },
69
+ referenceTo: {
70
+ type: "string",
71
+ description: "API name of the object to reference (for Lookup/MasterDetail)",
72
+ optional: true
73
+ },
74
+ relationshipLabel: {
75
+ type: "string",
76
+ description: "Label for the relationship (for Lookup/MasterDetail)",
77
+ optional: true
78
+ },
79
+ relationshipName: {
80
+ type: "string",
81
+ description: "API name for the relationship (for Lookup/MasterDetail)",
82
+ optional: true
83
+ },
84
+ deleteConstraint: {
85
+ type: "string",
86
+ enum: ["Cascade", "Restrict", "SetNull"],
87
+ description: "Delete constraint for Lookup fields",
88
+ optional: true
89
+ },
90
+ picklistValues: {
91
+ type: "array",
92
+ items: {
93
+ type: "object",
94
+ properties: {
95
+ label: { type: "string" },
96
+ isDefault: { type: "boolean", optional: true }
97
+ }
98
+ },
99
+ description: "Values for Picklist/MultiselectPicklist fields",
100
+ optional: true
101
+ },
102
+ description: {
103
+ type: "string",
104
+ description: "Description of the field",
105
+ optional: true
106
+ },
107
+ grantAccessTo: {
108
+ type: "array",
109
+ items: { type: "string" },
110
+ description: "Profile names to grant field access to (defaults to ['System Administrator'])",
111
+ optional: true
112
+ }
113
+ },
114
+ required: ["operation", "objectName", "fieldName"]
115
+ }
116
+ };
117
+ // Helper function to set field permissions (simplified version of the one in manageFieldPermissions.ts)
118
+ async function grantFieldPermissions(conn, objectName, fieldName, profileNames) {
119
+ try {
120
+ const fieldApiName = fieldName.endsWith('__c') || fieldName.includes('.') ? fieldName : `${fieldName}__c`;
121
+ const fullFieldName = `${objectName}.${fieldApiName}`;
122
+ // Get profile IDs
123
+ const profileQuery = await conn.query(`
124
+ SELECT Id, Name
125
+ FROM Profile
126
+ WHERE Name IN (${profileNames.map(name => `'${name}'`).join(', ')})
127
+ `);
128
+ if (profileQuery.records.length === 0) {
129
+ return { success: false, message: `No profiles found matching: ${profileNames.join(', ')}` };
130
+ }
131
+ const results = [];
132
+ const errors = [];
133
+ for (const profile of profileQuery.records) {
134
+ try {
135
+ // Check if permission already exists
136
+ const existingPerm = await conn.query(`
137
+ SELECT Id, PermissionsRead, PermissionsEdit
138
+ FROM FieldPermissions
139
+ WHERE ParentId IN (
140
+ SELECT Id FROM PermissionSet
141
+ WHERE IsOwnedByProfile = true
142
+ AND ProfileId = '${profile.Id}'
143
+ )
144
+ AND Field = '${fullFieldName}'
145
+ AND SobjectType = '${objectName}'
146
+ LIMIT 1
147
+ `);
148
+ if (existingPerm.records.length > 0) {
149
+ // Update existing permission
150
+ await conn.sobject('FieldPermissions').update({
151
+ Id: existingPerm.records[0].Id,
152
+ PermissionsRead: true,
153
+ PermissionsEdit: true
154
+ });
155
+ results.push(profile.Name);
156
+ }
157
+ else {
158
+ // Get the PermissionSet ID for this profile
159
+ const permSetQuery = await conn.query(`
160
+ SELECT Id FROM PermissionSet
161
+ WHERE IsOwnedByProfile = true
162
+ AND ProfileId = '${profile.Id}'
163
+ LIMIT 1
164
+ `);
165
+ if (permSetQuery.records.length > 0) {
166
+ // Create new permission
167
+ await conn.sobject('FieldPermissions').create({
168
+ ParentId: permSetQuery.records[0].Id,
169
+ SobjectType: objectName,
170
+ Field: fullFieldName,
171
+ PermissionsRead: true,
172
+ PermissionsEdit: true
173
+ });
174
+ results.push(profile.Name);
175
+ }
176
+ else {
177
+ errors.push(profile.Name);
178
+ }
179
+ }
180
+ }
181
+ catch (error) {
182
+ errors.push(profile.Name);
183
+ console.error(`Error granting permission to ${profile.Name}:`, error);
184
+ }
185
+ }
186
+ if (results.length > 0) {
187
+ return {
188
+ success: true,
189
+ message: `Field Level Security granted to: ${results.join(', ')}${errors.length > 0 ? `. Failed for: ${errors.join(', ')}` : ''}`
190
+ };
191
+ }
192
+ else {
193
+ return {
194
+ success: false,
195
+ message: `Could not grant Field Level Security to any profiles.`
196
+ };
197
+ }
198
+ }
199
+ catch (error) {
200
+ console.error('Error granting field permissions:', error);
201
+ return {
202
+ success: false,
203
+ message: `Field Level Security configuration failed.`
204
+ };
205
+ }
206
+ }
207
+ export async function handleManageField(conn, args) {
208
+ const { operation, objectName, fieldName, type, grantAccessTo, ...fieldProps } = args;
209
+ try {
210
+ if (operation === 'create') {
211
+ if (!type) {
212
+ throw new Error('Field type is required for field creation');
213
+ }
214
+ // Prepare base metadata for the new field
215
+ const metadata = {
216
+ fullName: `${objectName}.${fieldName}__c`,
217
+ label: fieldProps.label || fieldName,
218
+ type,
219
+ ...(fieldProps.required && { required: fieldProps.required }),
220
+ ...(fieldProps.unique && { unique: fieldProps.unique }),
221
+ ...(fieldProps.externalId && { externalId: fieldProps.externalId }),
222
+ ...(fieldProps.description && { description: fieldProps.description })
223
+ };
224
+ // Add type-specific properties
225
+ switch (type) {
226
+ case 'MasterDetail':
227
+ case 'Lookup':
228
+ if (fieldProps.referenceTo) {
229
+ metadata.referenceTo = fieldProps.referenceTo;
230
+ metadata.relationshipName = fieldProps.relationshipName;
231
+ metadata.relationshipLabel = fieldProps.relationshipLabel || fieldProps.relationshipName;
232
+ if (type === 'Lookup' && fieldProps.deleteConstraint) {
233
+ metadata.deleteConstraint = fieldProps.deleteConstraint;
234
+ }
235
+ }
236
+ break;
237
+ case 'TextArea':
238
+ metadata.type = 'LongTextArea';
239
+ metadata.length = fieldProps.length || 32768;
240
+ metadata.visibleLines = 3;
241
+ break;
242
+ case 'Text':
243
+ if (fieldProps.length) {
244
+ metadata.length = fieldProps.length;
245
+ }
246
+ break;
247
+ case 'Number':
248
+ if (fieldProps.precision) {
249
+ metadata.precision = fieldProps.precision;
250
+ metadata.scale = fieldProps.scale || 0;
251
+ }
252
+ break;
253
+ case 'Picklist':
254
+ case 'MultiselectPicklist':
255
+ if (fieldProps.picklistValues) {
256
+ metadata.valueSet = {
257
+ valueSetDefinition: {
258
+ sorted: true,
259
+ value: fieldProps.picklistValues.map(val => ({
260
+ fullName: val.label,
261
+ default: val.isDefault || false,
262
+ label: val.label
263
+ }))
264
+ }
265
+ };
266
+ }
267
+ break;
268
+ }
269
+ // Create the field
270
+ const result = await conn.metadata.create('CustomField', metadata);
271
+ if (result && (Array.isArray(result) ? result[0].success : result.success)) {
272
+ let permissionMessage = '';
273
+ // Grant Field Level Security (default to System Administrator if not specified)
274
+ const profilesToGrant = grantAccessTo && grantAccessTo.length > 0 ? grantAccessTo : ['System Administrator'];
275
+ // Wait a moment for field to be fully created
276
+ await new Promise(resolve => setTimeout(resolve, 2000));
277
+ const permissionResult = await grantFieldPermissions(conn, objectName, fieldName, profilesToGrant);
278
+ permissionMessage = `\n${permissionResult.message}`;
279
+ return {
280
+ content: [{
281
+ type: "text",
282
+ text: `Successfully created custom field ${fieldName}__c on ${objectName}.${permissionMessage}`
283
+ }],
284
+ isError: false,
285
+ };
286
+ }
287
+ }
288
+ else {
289
+ // For update, first get existing metadata
290
+ const existingMetadata = await conn.metadata.read('CustomField', [`${objectName}.${fieldName}__c`]);
291
+ const currentMetadata = Array.isArray(existingMetadata) ? existingMetadata[0] : existingMetadata;
292
+ if (!currentMetadata) {
293
+ throw new Error(`Field ${fieldName}__c not found on object ${objectName}`);
294
+ }
295
+ // Prepare update metadata
296
+ const metadata = {
297
+ ...currentMetadata,
298
+ ...(fieldProps.label && { label: fieldProps.label }),
299
+ ...(fieldProps.required !== undefined && { required: fieldProps.required }),
300
+ ...(fieldProps.unique !== undefined && { unique: fieldProps.unique }),
301
+ ...(fieldProps.externalId !== undefined && { externalId: fieldProps.externalId }),
302
+ ...(fieldProps.description !== undefined && { description: fieldProps.description }),
303
+ ...(fieldProps.length && { length: fieldProps.length }),
304
+ ...(fieldProps.precision && { precision: fieldProps.precision, scale: fieldProps.scale || 0 })
305
+ };
306
+ // Special handling for picklist values if provided
307
+ if (fieldProps.picklistValues &&
308
+ (currentMetadata.type === 'Picklist' || currentMetadata.type === 'MultiselectPicklist')) {
309
+ metadata.valueSet = {
310
+ valueSetDefinition: {
311
+ sorted: true,
312
+ value: fieldProps.picklistValues.map(val => ({
313
+ fullName: val.label,
314
+ default: val.isDefault || false,
315
+ label: val.label
316
+ }))
317
+ }
318
+ };
319
+ }
320
+ // Update the field
321
+ const result = await conn.metadata.update('CustomField', metadata);
322
+ if (result && (Array.isArray(result) ? result[0].success : result.success)) {
323
+ return {
324
+ content: [{
325
+ type: "text",
326
+ text: `Successfully updated custom field ${fieldName}__c on ${objectName}`
327
+ }],
328
+ isError: false,
329
+ };
330
+ }
331
+ }
332
+ return {
333
+ content: [{
334
+ type: "text",
335
+ text: `Failed to ${operation} custom field ${fieldName}__c`
336
+ }],
337
+ isError: true,
338
+ };
339
+ }
340
+ catch (error) {
341
+ return {
342
+ content: [{
343
+ type: "text",
344
+ text: `Error ${operation === 'create' ? 'creating' : 'updating'} custom field: ${error instanceof Error ? error.message : String(error)}`
345
+ }],
346
+ isError: true,
347
+ };
348
+ }
349
+ }
@@ -0,0 +1,17 @@
1
+ import { Tool } from "@modelcontextprotocol/sdk/types.js";
2
+ export declare const MANAGE_FIELD_PERMISSIONS: Tool;
3
+ export interface ManageFieldPermissionsArgs {
4
+ operation: 'grant' | 'revoke' | 'view';
5
+ objectName: string;
6
+ fieldName: string;
7
+ profileNames?: string[];
8
+ readable?: boolean;
9
+ editable?: boolean;
10
+ }
11
+ export declare function handleManageFieldPermissions(conn: any, args: ManageFieldPermissionsArgs): Promise<{
12
+ content: {
13
+ type: string;
14
+ text: string;
15
+ }[];
16
+ isError: boolean;
17
+ }>;
@@ -0,0 +1,247 @@
1
+ export const MANAGE_FIELD_PERMISSIONS = {
2
+ name: "salesforce_manage_field_permissions",
3
+ description: `Manage Field Level Security (Field Permissions) for custom and standard fields.
4
+ - Grant or revoke read/edit access to fields for specific profiles or permission sets
5
+ - View current field permissions
6
+ - Bulk update permissions for multiple profiles
7
+
8
+ Examples:
9
+ 1. Grant System Administrator access to a field
10
+ 2. Give read-only access to a field for specific profiles
11
+ 3. Check which profiles have access to a field`,
12
+ inputSchema: {
13
+ type: "object",
14
+ properties: {
15
+ operation: {
16
+ type: "string",
17
+ enum: ["grant", "revoke", "view"],
18
+ description: "Operation to perform on field permissions"
19
+ },
20
+ objectName: {
21
+ type: "string",
22
+ description: "API name of the object (e.g., 'Account', 'Custom_Object__c')"
23
+ },
24
+ fieldName: {
25
+ type: "string",
26
+ description: "API name of the field (e.g., 'Custom_Field__c')"
27
+ },
28
+ profileNames: {
29
+ type: "array",
30
+ items: { type: "string" },
31
+ description: "Names of profiles to grant/revoke access (e.g., ['System Administrator', 'Sales User'])",
32
+ optional: true
33
+ },
34
+ readable: {
35
+ type: "boolean",
36
+ description: "Grant/revoke read access (default: true)",
37
+ optional: true
38
+ },
39
+ editable: {
40
+ type: "boolean",
41
+ description: "Grant/revoke edit access (default: true)",
42
+ optional: true
43
+ }
44
+ },
45
+ required: ["operation", "objectName", "fieldName"]
46
+ }
47
+ };
48
+ export async function handleManageFieldPermissions(conn, args) {
49
+ const { operation, objectName, fieldName, readable = true, editable = true } = args;
50
+ let { profileNames } = args;
51
+ try {
52
+ // Ensure field name has __c suffix if it's a custom field and doesn't already have it
53
+ const fieldApiName = fieldName.endsWith('__c') || fieldName.includes('.') ? fieldName : `${fieldName}__c`;
54
+ const fullFieldName = `${objectName}.${fieldApiName}`;
55
+ if (operation === 'view') {
56
+ // Query existing field permissions
57
+ const permissionsQuery = `
58
+ SELECT Id, Parent.ProfileId, Parent.Profile.Name, Parent.IsOwnedByProfile,
59
+ Parent.PermissionSetId, Parent.PermissionSet.Name,
60
+ Field, PermissionsRead, PermissionsEdit
61
+ FROM FieldPermissions
62
+ WHERE SobjectType = '${objectName}'
63
+ AND Field = '${fullFieldName}'
64
+ ORDER BY Parent.Profile.Name
65
+ `;
66
+ const result = await conn.query(permissionsQuery);
67
+ if (result.records.length === 0) {
68
+ return {
69
+ content: [{
70
+ type: "text",
71
+ text: `No field permissions found for ${fullFieldName}. This field might not have any specific permissions set, or it might be universally accessible.`
72
+ }],
73
+ isError: false,
74
+ };
75
+ }
76
+ let responseText = `Field permissions for ${fullFieldName}:\n\n`;
77
+ result.records.forEach((perm) => {
78
+ const name = perm.Parent.IsOwnedByProfile
79
+ ? perm.Parent.Profile?.Name
80
+ : perm.Parent.PermissionSet?.Name;
81
+ const type = perm.Parent.IsOwnedByProfile ? 'Profile' : 'Permission Set';
82
+ responseText += `${type}: ${name}\n`;
83
+ responseText += ` - Read Access: ${perm.PermissionsRead ? 'Yes' : 'No'}\n`;
84
+ responseText += ` - Edit Access: ${perm.PermissionsEdit ? 'Yes' : 'No'}\n\n`;
85
+ });
86
+ return {
87
+ content: [{
88
+ type: "text",
89
+ text: responseText
90
+ }],
91
+ isError: false,
92
+ };
93
+ }
94
+ // For grant/revoke operations
95
+ if (!profileNames || profileNames.length === 0) {
96
+ // If no profiles specified, default to System Administrator
97
+ profileNames = ['System Administrator'];
98
+ }
99
+ // Get profile IDs
100
+ const profileQuery = await conn.query(`
101
+ SELECT Id, Name
102
+ FROM Profile
103
+ WHERE Name IN (${profileNames.map(name => `'${name}'`).join(', ')})
104
+ `);
105
+ if (profileQuery.records.length === 0) {
106
+ return {
107
+ content: [{
108
+ type: "text",
109
+ text: `No profiles found matching: ${profileNames.join(', ')}`
110
+ }],
111
+ isError: true,
112
+ };
113
+ }
114
+ const results = [];
115
+ const errors = [];
116
+ for (const profile of profileQuery.records) {
117
+ try {
118
+ if (operation === 'grant') {
119
+ // First, check if permission already exists
120
+ const existingPerm = await conn.query(`
121
+ SELECT Id, PermissionsRead, PermissionsEdit
122
+ FROM FieldPermissions
123
+ WHERE ParentId IN (
124
+ SELECT Id FROM PermissionSet
125
+ WHERE IsOwnedByProfile = true
126
+ AND ProfileId = '${profile.Id}'
127
+ )
128
+ AND Field = '${fullFieldName}'
129
+ AND SobjectType = '${objectName}'
130
+ LIMIT 1
131
+ `);
132
+ if (existingPerm.records.length > 0) {
133
+ // Update existing permission
134
+ const updateResult = await conn.sobject('FieldPermissions').update({
135
+ Id: existingPerm.records[0].Id,
136
+ PermissionsRead: readable,
137
+ PermissionsEdit: editable && readable // Edit requires read
138
+ });
139
+ results.push({
140
+ profile: profile.Name,
141
+ action: 'updated',
142
+ success: updateResult.success
143
+ });
144
+ }
145
+ else {
146
+ // Get the PermissionSet ID for this profile
147
+ const permSetQuery = await conn.query(`
148
+ SELECT Id FROM PermissionSet
149
+ WHERE IsOwnedByProfile = true
150
+ AND ProfileId = '${profile.Id}'
151
+ LIMIT 1
152
+ `);
153
+ if (permSetQuery.records.length > 0) {
154
+ // Create new permission
155
+ const createResult = await conn.sobject('FieldPermissions').create({
156
+ ParentId: permSetQuery.records[0].Id,
157
+ SobjectType: objectName,
158
+ Field: fullFieldName,
159
+ PermissionsRead: readable,
160
+ PermissionsEdit: editable && readable // Edit requires read
161
+ });
162
+ results.push({
163
+ profile: profile.Name,
164
+ action: 'created',
165
+ success: createResult.success
166
+ });
167
+ }
168
+ else {
169
+ errors.push(`Could not find permission set for profile: ${profile.Name}`);
170
+ }
171
+ }
172
+ }
173
+ else if (operation === 'revoke') {
174
+ // Find and delete the permission
175
+ const existingPerm = await conn.query(`
176
+ SELECT Id
177
+ FROM FieldPermissions
178
+ WHERE ParentId IN (
179
+ SELECT Id FROM PermissionSet
180
+ WHERE IsOwnedByProfile = true
181
+ AND ProfileId = '${profile.Id}'
182
+ )
183
+ AND Field = '${fullFieldName}'
184
+ AND SobjectType = '${objectName}'
185
+ LIMIT 1
186
+ `);
187
+ if (existingPerm.records.length > 0) {
188
+ const deleteResult = await conn.sobject('FieldPermissions').delete(existingPerm.records[0].Id);
189
+ results.push({
190
+ profile: profile.Name,
191
+ action: 'revoked',
192
+ success: true
193
+ });
194
+ }
195
+ else {
196
+ results.push({
197
+ profile: profile.Name,
198
+ action: 'no permission found',
199
+ success: true
200
+ });
201
+ }
202
+ }
203
+ }
204
+ catch (error) {
205
+ errors.push(`${profile.Name}: ${error instanceof Error ? error.message : String(error)}`);
206
+ }
207
+ }
208
+ // Format response
209
+ let responseText = `Field permission ${operation} operation completed for ${fullFieldName}:\n\n`;
210
+ const successful = results.filter(r => r.success);
211
+ const failed = results.filter(r => !r.success);
212
+ if (successful.length > 0) {
213
+ responseText += 'Successful:\n';
214
+ successful.forEach(r => {
215
+ responseText += ` - ${r.profile}: ${r.action}\n`;
216
+ });
217
+ }
218
+ if (failed.length > 0 || errors.length > 0) {
219
+ responseText += '\nFailed:\n';
220
+ failed.forEach(r => {
221
+ responseText += ` - ${r.profile}: ${r.action}\n`;
222
+ });
223
+ errors.forEach(e => {
224
+ responseText += ` - ${e}\n`;
225
+ });
226
+ }
227
+ if (operation === 'grant') {
228
+ responseText += `\nPermissions granted:\n - Read: ${readable ? 'Yes' : 'No'}\n - Edit: ${editable ? 'Yes' : 'No'}`;
229
+ }
230
+ return {
231
+ content: [{
232
+ type: "text",
233
+ text: responseText
234
+ }],
235
+ isError: false,
236
+ };
237
+ }
238
+ catch (error) {
239
+ return {
240
+ content: [{
241
+ type: "text",
242
+ text: `Error managing field permissions: ${error instanceof Error ? error.message : String(error)}`
243
+ }],
244
+ isError: true,
245
+ };
246
+ }
247
+ }
@@ -0,0 +1,20 @@
1
+ import { Tool } from "@modelcontextprotocol/sdk/types.js";
2
+ export declare const MANAGE_OBJECT: Tool;
3
+ export interface ManageObjectArgs {
4
+ operation: 'create' | 'update';
5
+ objectName: string;
6
+ label?: string;
7
+ pluralLabel?: string;
8
+ description?: string;
9
+ nameFieldLabel?: string;
10
+ nameFieldType?: 'Text' | 'AutoNumber';
11
+ nameFieldFormat?: string;
12
+ sharingModel?: 'ReadWrite' | 'Read' | 'Private' | 'ControlledByParent';
13
+ }
14
+ export declare function handleManageObject(conn: any, args: ManageObjectArgs): Promise<{
15
+ content: {
16
+ type: string;
17
+ text: string;
18
+ }[];
19
+ isError: boolean;
20
+ }>;