salesforce_manage_field_permissions
Manage Salesforce field permissions by granting, revoking, or viewing read/edit access for profiles and permission sets to control data visibility and security.
Instructions
Manage Field Level Security (Field Permissions) for custom and standard fields.
Grant or revoke read/edit access to fields for specific profiles or permission sets
View current field permissions
Bulk update permissions for multiple profiles
Examples:
Grant System Administrator access to a field
Give read-only access to a field for specific profiles
Check which profiles have access to a field
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| operation | Yes | Operation to perform on field permissions | |
| objectName | Yes | API name of the object (e.g., 'Account', 'Custom_Object__c') | |
| fieldName | Yes | API name of the field (e.g., 'Custom_Field__c') | |
| profileNames | No | Names of profiles to grant/revoke access (e.g., ['System Administrator', 'Sales User']) | |
| readable | No | Grant/revoke read access (default: true) | |
| editable | No | Grant/revoke edit access (default: true) |
Implementation Reference
- The main execution handler for the 'salesforce_manage_field_permissions' tool. Handles 'grant', 'revoke', and 'view' operations on Field Level Security by querying, creating, updating, or deleting FieldPermissions records in Salesforce.export async function handleManageFieldPermissions(conn: any, args: ManageFieldPermissionsArgs) { const { operation, objectName, fieldName, readable = true, editable = true } = args; let { profileNames } = args; try { // Ensure field name has __c suffix if it's a custom field and doesn't already have it const fieldApiName = fieldName.endsWith('__c') || fieldName.includes('.') ? fieldName : `${fieldName}__c`; const fullFieldName = `${objectName}.${fieldApiName}`; if (operation === 'view') { // Query existing field permissions const permissionsQuery = ` SELECT Id, Parent.ProfileId, Parent.Profile.Name, Parent.IsOwnedByProfile, Parent.PermissionSetId, Parent.PermissionSet.Name, Field, PermissionsRead, PermissionsEdit FROM FieldPermissions WHERE SobjectType = '${objectName}' AND Field = '${fullFieldName}' ORDER BY Parent.Profile.Name `; const result = await conn.query(permissionsQuery); if (result.records.length === 0) { return { content: [{ type: "text", text: `No field permissions found for ${fullFieldName}. This field might not have any specific permissions set, or it might be universally accessible.` }], isError: false, }; } let responseText = `Field permissions for ${fullFieldName}:\n\n`; result.records.forEach((perm: any) => { const name = perm.Parent.IsOwnedByProfile ? perm.Parent.Profile?.Name : perm.Parent.PermissionSet?.Name; const type = perm.Parent.IsOwnedByProfile ? 'Profile' : 'Permission Set'; responseText += `${type}: ${name}\n`; responseText += ` - Read Access: ${perm.PermissionsRead ? 'Yes' : 'No'}\n`; responseText += ` - Edit Access: ${perm.PermissionsEdit ? 'Yes' : 'No'}\n\n`; }); return { content: [{ type: "text", text: responseText }], isError: false, }; } // For grant/revoke operations if (!profileNames || profileNames.length === 0) { // If no profiles specified, default to System Administrator profileNames = ['System Administrator']; } // Get profile IDs const profileQuery = await conn.query(` SELECT Id, Name FROM Profile WHERE Name IN (${profileNames.map(name => `'${name}'`).join(', ')}) `); if (profileQuery.records.length === 0) { return { content: [{ type: "text", text: `No profiles found matching: ${profileNames.join(', ')}` }], isError: true, }; } const results: any[] = []; const errors: string[] = []; for (const profile of profileQuery.records) { try { if (operation === 'grant') { // First, check if permission already exists const existingPerm = await conn.query(` SELECT Id, PermissionsRead, PermissionsEdit FROM FieldPermissions WHERE ParentId IN ( SELECT Id FROM PermissionSet WHERE IsOwnedByProfile = true AND ProfileId = '${profile.Id}' ) AND Field = '${fullFieldName}' AND SobjectType = '${objectName}' LIMIT 1 `); if (existingPerm.records.length > 0) { // Update existing permission const updateResult = await conn.sobject('FieldPermissions').update({ Id: existingPerm.records[0].Id, PermissionsRead: readable, PermissionsEdit: editable && readable // Edit requires read }); results.push({ profile: profile.Name, action: 'updated', success: updateResult.success }); } else { // Get the PermissionSet ID for this profile const permSetQuery = await conn.query(` SELECT Id FROM PermissionSet WHERE IsOwnedByProfile = true AND ProfileId = '${profile.Id}' LIMIT 1 `); if (permSetQuery.records.length > 0) { // Create new permission const createResult = await conn.sobject('FieldPermissions').create({ ParentId: permSetQuery.records[0].Id, SobjectType: objectName, Field: fullFieldName, PermissionsRead: readable, PermissionsEdit: editable && readable // Edit requires read }); results.push({ profile: profile.Name, action: 'created', success: createResult.success }); } else { errors.push(`Could not find permission set for profile: ${profile.Name}`); } } } else if (operation === 'revoke') { // Find and delete the permission const existingPerm = await conn.query(` SELECT Id FROM FieldPermissions WHERE ParentId IN ( SELECT Id FROM PermissionSet WHERE IsOwnedByProfile = true AND ProfileId = '${profile.Id}' ) AND Field = '${fullFieldName}' AND SobjectType = '${objectName}' LIMIT 1 `); if (existingPerm.records.length > 0) { const deleteResult = await conn.sobject('FieldPermissions').delete(existingPerm.records[0].Id); results.push({ profile: profile.Name, action: 'revoked', success: true }); } else { results.push({ profile: profile.Name, action: 'no permission found', success: true }); } } } catch (error) { errors.push(`${profile.Name}: ${error instanceof Error ? error.message : String(error)}`); } } // Format response let responseText = `Field permission ${operation} operation completed for ${fullFieldName}:\n\n`; const successful = results.filter(r => r.success); const failed = results.filter(r => !r.success); if (successful.length > 0) { responseText += 'Successful:\n'; successful.forEach(r => { responseText += ` - ${r.profile}: ${r.action}\n`; }); } if (failed.length > 0 || errors.length > 0) { responseText += '\nFailed:\n'; failed.forEach(r => { responseText += ` - ${r.profile}: ${r.action}\n`; }); errors.forEach(e => { responseText += ` - ${e}\n`; }); } if (operation === 'grant') { responseText += `\nPermissions granted:\n - Read: ${readable ? 'Yes' : 'No'}\n - Edit: ${editable ? 'Yes' : 'No'}`; } return { content: [{ type: "text", text: responseText }], isError: false, }; } catch (error) { return { content: [{ type: "text", text: `Error managing field permissions: ${error instanceof Error ? error.message : String(error)}` }], isError: true, }; } }
- Tool definition including name, description, and input schema for validating arguments to the salesforce_manage_field_permissions tool.export const MANAGE_FIELD_PERMISSIONS: Tool = { name: "salesforce_manage_field_permissions", description: `Manage Field Level Security (Field Permissions) for custom and standard fields. - Grant or revoke read/edit access to fields for specific profiles or permission sets - View current field permissions - Bulk update permissions for multiple profiles Examples: 1. Grant System Administrator access to a field 2. Give read-only access to a field for specific profiles 3. Check which profiles have access to a field`, inputSchema: { type: "object", properties: { operation: { type: "string", enum: ["grant", "revoke", "view"], description: "Operation to perform on field permissions" }, objectName: { type: "string", description: "API name of the object (e.g., 'Account', 'Custom_Object__c')" }, fieldName: { type: "string", description: "API name of the field (e.g., 'Custom_Field__c')" }, profileNames: { type: "array", items: { type: "string" }, description: "Names of profiles to grant/revoke access (e.g., ['System Administrator', 'Sales User'])", optional: true }, readable: { type: "boolean", description: "Grant/revoke read access (default: true)", optional: true }, editable: { type: "boolean", description: "Grant/revoke edit access (default: true)", optional: true } }, required: ["operation", "objectName", "fieldName"] } };
- src/index.ts:180-194 (registration)Dispatcher registration in the main tool switch statement that validates input and calls the handleManageFieldPermissions function.case "salesforce_manage_field_permissions": { const permArgs = args as Record<string, unknown>; if (!permArgs.operation || !permArgs.objectName || !permArgs.fieldName) { throw new Error('operation, objectName, and fieldName are required for field permissions management'); } const validatedArgs: ManageFieldPermissionsArgs = { operation: permArgs.operation as 'grant' | 'revoke' | 'view', objectName: permArgs.objectName as string, fieldName: permArgs.fieldName as string, profileNames: permArgs.profileNames as string[] | undefined, readable: permArgs.readable as boolean | undefined, editable: permArgs.editable as boolean | undefined }; return await handleManageFieldPermissions(conn, validatedArgs); }
- src/index.ts:45-63 (registration)Registration of the tool in the listTools response, making it discoverable by MCP clients.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:19-19 (registration)Import of the tool schema, handler, and types from the implementation file.import { MANAGE_FIELD_PERMISSIONS, handleManageFieldPermissions, ManageFieldPermissionsArgs } from "./tools/manageFieldPermissions.js";