Skip to main content
Glama
tsmztech

Salesforce MCP Server

salesforce_manage_field_permissions

Manage Salesforce field permissions by granting, revoking, or viewing read/edit access for profiles and permission sets on custom and standard fields.

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:

  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

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
operationYesOperation to perform on field permissions
objectNameYesAPI name of the object (e.g., 'Account', 'Custom_Object__c')
fieldNameYesAPI name of the field (e.g., 'Custom_Field__c')
profileNamesNoNames of profiles to grant/revoke access (e.g., ['System Administrator', 'Sales User'])
readableNoGrant/revoke read access (default: true)
editableNoGrant/revoke edit access (default: true)

Implementation Reference

  • The primary handler function executing the tool's logic: handles 'grant', 'revoke', 'view' operations on Salesforce FieldPermissions for profiles via queries and DML.
    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,
        };
      }
    } 
  • Defines the tool schema including name, description, and inputSchema for validation of parameters like operation (grant/revoke/view), objectName, fieldName, etc.
    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)
    Registers the tool handler in the CallToolRequest switch statement, validates arguments and calls handleManageFieldPermissions.
    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)
    Includes the tool in the list returned by ListToolsRequestHandler.
    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
      ],
    }));
  • TypeScript interface defining the input arguments for the handler, used in index.ts for validation.
    export interface ManageFieldPermissionsArgs {
      operation: 'grant' | 'revoke' | 'view';
      objectName: string;
      fieldName: string;
      profileNames?: string[];
      readable?: boolean;
      editable?: boolean;
    }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/tsmztech/mcp-server-salesforce'

If you have feedback or need assistance with the MCP directory API, please join our Discord server