Skip to main content
Glama

salesforce_manage_field

Create or modify custom fields on Salesforce objects to customize data structures and relationships for business needs.

Instructions

Create new custom fields or modify existing fields on any Salesforce object:

  • Field Types: Text, Number, Date, Lookup, Master-Detail, Picklist etc.

  • Properties: Required, Unique, External ID, Length, Scale etc.

  • Relationships: Create lookups and master-detail relationships Examples: Add Rating__c picklist to Account, Create Account lookup on Custom Object Note: Changes affect metadata and require proper permissions

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
operationYesWhether to create new field or update existing
objectNameYesAPI name of the object to add/modify the field
fieldNameYesAPI name for the field (without __c suffix)
labelNoLabel for the field
typeNoField type (required for create)
requiredNoWhether the field is required
uniqueNoWhether the field value must be unique
externalIdNoWhether the field is an external ID
lengthNoLength for text fields
precisionNoPrecision for numeric fields
scaleNoScale for numeric fields
referenceToNoAPI name of the object to reference (for Lookup/MasterDetail)
relationshipLabelNoLabel for the relationship (for Lookup/MasterDetail)
relationshipNameNoAPI name for the relationship (for Lookup/MasterDetail)
deleteConstraintNoDelete constraint for Lookup fields
picklistValuesNoValues for Picklist/MultiselectPicklist fields
descriptionNoDescription of the field

Implementation Reference

  • The handleManageField function implements the core tool logic: creates or updates custom fields on Salesforce objects using the Metadata API. Handles various field types (Text, Number, Picklist, Lookup, MasterDetail), properties (required, unique, length, etc.), relationships, and picklist values.
    export async function handleManageField(conn: any, args: ManageFieldArgs) {
      const { operation, objectName, fieldName, type, ...fieldProps } = args;
    
      try {
        if (operation === 'create') {
          if (!type) {
            throw new Error('Field type is required for field creation');
          }
    
          // Prepare base metadata for the new field
          const metadata: FieldMetadataInfo = {
            fullName: `${objectName}.${fieldName}__c`,
            label: fieldProps.label || fieldName,
            type,
            ...(fieldProps.required && { required: fieldProps.required }),
            ...(fieldProps.unique && { unique: fieldProps.unique }),
            ...(fieldProps.externalId && { externalId: fieldProps.externalId }),
            ...(fieldProps.description && { description: fieldProps.description })
          };
    
          // Add type-specific properties
          switch (type) {
            case 'MasterDetail':
            case 'Lookup':
              if (fieldProps.referenceTo) {
                metadata.referenceTo = fieldProps.referenceTo;
                metadata.relationshipName = fieldProps.relationshipName;
                metadata.relationshipLabel = fieldProps.relationshipLabel || fieldProps.relationshipName;
                if (type === 'Lookup' && fieldProps.deleteConstraint) {
                  metadata.deleteConstraint = fieldProps.deleteConstraint;
                }
              }
              break;
    
            case 'TextArea':
              metadata.type = 'LongTextArea';
              metadata.length = fieldProps.length || 32768;
              metadata.visibleLines = 3;
              break;
    
            case 'Text':
              if (fieldProps.length) {
                metadata.length = fieldProps.length;
              }
              break;
    
            case 'Number':
              if (fieldProps.precision) {
                metadata.precision = fieldProps.precision;
                metadata.scale = fieldProps.scale || 0;
              }
              break;
    
            case 'Picklist':
            case 'MultiselectPicklist':
              if (fieldProps.picklistValues) {
                metadata.valueSet = {
                  valueSetDefinition: {
                    sorted: true,
                    value: fieldProps.picklistValues.map(val => ({
                      fullName: val.label,
                      default: val.isDefault || false,
                      label: val.label
                    }))
                  }
                };
              }
              break;
          }
    
          // Create the field
          const result = await conn.metadata.create('CustomField', metadata);
    
          if (result && (Array.isArray(result) ? result[0].success : result.success)) {
            return {
              content: [{
                type: "text",
                text: `Successfully created custom field ${fieldName}__c on ${objectName}`
              }],
              isError: false,
            };
          }
        } else {
          // For update, first get existing metadata
          const existingMetadata = await conn.metadata.read('CustomField', [`${objectName}.${fieldName}__c`]);
          const currentMetadata = Array.isArray(existingMetadata) ? existingMetadata[0] : existingMetadata;
    
          if (!currentMetadata) {
            throw new Error(`Field ${fieldName}__c not found on object ${objectName}`);
          }
    
          // Prepare update metadata
          const metadata: FieldMetadataInfo = {
            ...currentMetadata,
            ...(fieldProps.label && { label: fieldProps.label }),
            ...(fieldProps.required !== undefined && { required: fieldProps.required }),
            ...(fieldProps.unique !== undefined && { unique: fieldProps.unique }),
            ...(fieldProps.externalId !== undefined && { externalId: fieldProps.externalId }),
            ...(fieldProps.description !== undefined && { description: fieldProps.description }),
            ...(fieldProps.length && { length: fieldProps.length }),
            ...(fieldProps.precision && { precision: fieldProps.precision, scale: fieldProps.scale || 0 })
          };
    
          // Special handling for picklist values if provided
          if (fieldProps.picklistValues && 
              (currentMetadata.type === 'Picklist' || currentMetadata.type === 'MultiselectPicklist')) {
            metadata.valueSet = {
              valueSetDefinition: {
                sorted: true,
                value: fieldProps.picklistValues.map(val => ({
                  fullName: val.label,
                  default: val.isDefault || false,
                  label: val.label
                }))
              }
            };
          }
    
          // Update the field
          const result = await conn.metadata.update('CustomField', metadata);
    
          if (result && (Array.isArray(result) ? result[0].success : result.success)) {
            return {
              content: [{
                type: "text",
                text: `Successfully updated custom field ${fieldName}__c on ${objectName}`
              }],
              isError: false,
            };
          }
        }
    
        return {
          content: [{
            type: "text",
            text: `Failed to ${operation} custom field ${fieldName}__c`
          }],
          isError: true,
        };
    
      } catch (error) {
        return {
          content: [{
            type: "text",
            text: `Error ${operation === 'create' ? 'creating' : 'updating'} custom field: ${error instanceof Error ? error.message : String(error)}`
          }],
          isError: true,
        };
      }
    }
  • Defines the MCP Tool object MANAGE_FIELD with name 'salesforce_manage_field', detailed description, and comprehensive inputSchema specifying parameters like operation (create/update), objectName, fieldName, type, required, length, picklistValues, referenceTo for lookups, etc.
    export const MANAGE_FIELD: Tool = {
      name: "salesforce_manage_field",
      description: `Create new custom fields or modify existing fields on any Salesforce object:
      - Field Types: Text, Number, Date, Lookup, Master-Detail, Picklist etc.
      - Properties: Required, Unique, External ID, Length, Scale etc.
      - Relationships: Create lookups and master-detail relationships
      Examples: Add Rating__c picklist to Account, Create Account lookup on Custom Object
      Note: Changes affect metadata and require proper permissions`,
      inputSchema: {
        type: "object",
        properties: {
          operation: {
            type: "string",
            enum: ["create", "update"],
            description: "Whether to create new field or update existing"
          },
          objectName: {
            type: "string",
            description: "API name of the object to add/modify the field"
          },
          fieldName: {
            type: "string",
            description: "API name for the field (without __c suffix)"
          },
          label: {
            type: "string",
            description: "Label for the field",
            optional: true
          },
          type: {
            type: "string",
            enum: ["Checkbox", "Currency", "Date", "DateTime", "Email", "Number", "Percent", 
                   "Phone", "Picklist", "MultiselectPicklist", "Text", "TextArea", "LongTextArea", 
                   "Html", "Url", "Lookup", "MasterDetail"],
            description: "Field type (required for create)",
            optional: true
          },
          required: {
            type: "boolean",
            description: "Whether the field is required",
            optional: true
          },
          unique: {
            type: "boolean",
            description: "Whether the field value must be unique",
            optional: true
          },
          externalId: {
            type: "boolean",
            description: "Whether the field is an external ID",
            optional: true
          },
          length: {
            type: "number",
            description: "Length for text fields",
            optional: true
          },
          precision: {
            type: "number",
            description: "Precision for numeric fields",
            optional: true
          },
          scale: {
            type: "number",
            description: "Scale for numeric fields",
            optional: true
          },
          referenceTo: {
            type: "string",
            description: "API name of the object to reference (for Lookup/MasterDetail)",
            optional: true
          },
          relationshipLabel: {
            type: "string",
            description: "Label for the relationship (for Lookup/MasterDetail)",
            optional: true
          },
          relationshipName: {
            type: "string",
            description: "API name for the relationship (for Lookup/MasterDetail)",
            optional: true
          },
          deleteConstraint: {
            type: "string",
            enum: ["Cascade", "Restrict", "SetNull"],
            description: "Delete constraint for Lookup fields",
            optional: true
          },
          picklistValues: {
            type: "array",
            items: {
              type: "object",
              properties: {
                label: { type: "string" },
                isDefault: { type: "boolean", optional: true }
              }
            },
            description: "Values for Picklist/MultiselectPicklist fields",
            optional: true
          },
          description: {
            type: "string",
            description: "Description of the field",
            optional: true
          }
        },
        required: ["operation", "objectName", "fieldName"]
      }
    };
  • src/index.ts:116-141 (registration)
    In the CallToolRequest handler switch case, validates input arguments conforming to ManageFieldArgs and invokes handleManageField with the Salesforce connection.
    case "salesforce_manage_field": {
      const fieldArgs = args as Record<string, unknown>;
      if (!fieldArgs.operation || !fieldArgs.objectName || !fieldArgs.fieldName) {
        throw new Error('operation, objectName, and fieldName are required for field management');
      }
      const validatedArgs: ManageFieldArgs = {
        operation: fieldArgs.operation as 'create' | 'update',
        objectName: fieldArgs.objectName as string,
        fieldName: fieldArgs.fieldName as string,
        label: fieldArgs.label as string | undefined,
        type: fieldArgs.type as string | undefined,
        required: fieldArgs.required as boolean | undefined,
        unique: fieldArgs.unique as boolean | undefined,
        externalId: fieldArgs.externalId as boolean | undefined,
        length: fieldArgs.length as number | undefined,
        precision: fieldArgs.precision as number | undefined,
        scale: fieldArgs.scale as number | undefined,
        referenceTo: fieldArgs.referenceTo as string | undefined,
        relationshipLabel: fieldArgs.relationshipLabel as string | undefined,
        relationshipName: fieldArgs.relationshipName as string | undefined,
        deleteConstraint: fieldArgs.deleteConstraint as 'Cascade' | 'Restrict' | 'SetNull' | undefined,
        picklistValues: fieldArgs.picklistValues as Array<{ label: string; isDefault?: boolean }> | undefined,
        description: fieldArgs.description as string | undefined
      };
      return await handleManageField(conn, validatedArgs);
    }
  • src/index.ts:35-45 (registration)
    Registers the MANAGE_FIELD tool in the ListToolsRequest handler by including it in the tools array returned to clients.
    server.setRequestHandler(ListToolsRequestSchema, async () => ({
      tools: [
        SEARCH_OBJECTS, 
        DESCRIBE_OBJECT, 
        QUERY_RECORDS, 
        DML_RECORDS,
        MANAGE_OBJECT,
        MANAGE_FIELD,
        SEARCH_ALL
      ],
    }));
  • src/index.ts:17-17 (registration)
    Imports the MANAGE_FIELD tool definition, handleManageField handler function, and ManageFieldArgs type from ./tools/manageField.js.
    import { MANAGE_FIELD, handleManageField, ManageFieldArgs } from "./tools/manageField.js";
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden of behavioral disclosure. It effectively communicates that this is a metadata mutation tool ('create new custom fields or modify existing fields'), specifies that 'changes affect metadata,' and notes permission requirements. It doesn't mention rate limits, side effects on existing data, or whether operations are reversible, but covers the essential safety and scope aspects for a metadata tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is efficiently structured with a clear opening statement followed by bullet-point categorization and specific examples. Every sentence earns its place by providing distinct value: the first sentence states the core purpose, the bullets organize parameter concepts, the examples illustrate use cases, and the note adds critical behavioral context. No wasted words.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a complex metadata mutation tool with 17 parameters and no annotations or output schema, the description does well by covering purpose, scope, permission requirements, and parameter categories. It could be more complete by explicitly mentioning that this tool doesn't handle data values (unlike salesforce_dml_records) or describing typical response formats, but it provides sufficient context for an agent to understand the tool's role and basic usage.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema description coverage is 100%, so the schema already documents all 17 parameters thoroughly. The description adds some value by categorizing parameters into 'Field Types,' 'Properties,' and 'Relationships,' which helps conceptual organization, but doesn't provide additional syntax, format, or constraint details beyond what's in the schema. This meets the baseline for high schema coverage.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's purpose with specific verbs ('create new custom fields or modify existing fields') and identifies the resource ('any Salesforce object'). It distinguishes this tool from siblings like salesforce_dml_records (data manipulation) and salesforce_describe_object (metadata inspection) by focusing on field-level metadata management.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides clear context for when to use this tool through examples ('Add Rating__c picklist to Account, Create Account lookup on Custom Object') and notes about prerequisites ('require proper permissions'). However, it doesn't explicitly state when NOT to use it or name specific alternatives among the sibling tools, though the context implies it's for field metadata rather than data operations.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

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/SurajAdsul/mcp-server-salesforce'

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