Skip to main content
Glama
usama-dtc

Salesforce MCP Server

by usama-dtc

salesforce_manage_field

Create or modify custom fields on Salesforce objects to customize data structures, define relationships, and configure field properties like picklists and validation rules.

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 main handler function that executes the salesforce_manage_field tool logic. It handles 'create' and 'update' operations on Salesforce custom fields using the Salesforce metadata API via conn.metadata.create/update.
    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,
        };
      }
    }
  • The Tool definition including name, description, and detailed inputSchema for validating parameters like operation, objectName, fieldName, type, picklistValues, 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:36-47 (registration)
    Registration of the tool in the MCP server's listTools handler, exporting MANAGE_FIELD for discovery.
    server.setRequestHandler(ListToolsRequestSchema, async () => ({
      tools: [
        SEARCH_OBJECTS, 
        DESCRIBE_OBJECT, 
        QUERY_RECORDS, 
        DML_RECORDS,
        MANAGE_OBJECT,
        MANAGE_FIELD,
        SEARCH_ALL,
        UPLOAD_REPORT_XML  // Add new tool to the list
      ],
    }));
  • src/index.ts:118-143 (registration)
    The switch case in the callTool handler that validates input arguments and invokes the handleManageField function.
    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);
    }
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 ('Changes affect metadata'), specifies permission requirements ('require proper permissions'), and provides examples of operations. It doesn't mention rate limits, error handling, or the impact on existing data, but covers the essential safety and scope aspects well for an unannotated 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-pointed categories and specific examples, then a critical note about permissions. Every sentence earns its place by providing distinct value: the purpose, parameter categories, concrete examples, and important constraints.

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 explaining the tool's purpose, scope, permission requirements, and providing examples. However, it doesn't describe what the tool returns (success/failure indicators, field IDs, etc.), which would be helpful given the absence of an output schema. The parameter coverage is handled by the schema, but behavioral context is adequately addressed.

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 context by listing categories of parameters ('Field Types', 'Properties', 'Relationships') and providing examples, but doesn't add significant semantic meaning beyond what's already in the parameter descriptions. 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 specific verb ('Create new custom fields or modify existing fields') and resource ('on any Salesforce object'), distinguishing it from siblings like salesforce_describe_object (metadata inspection), salesforce_dml_records (data manipulation), and salesforce_manage_object (object-level operations). It precisely defines the scope of field management operations.

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 (creating/modifying fields with specific types and properties) and mentions prerequisites ('require proper permissions'). However, it doesn't explicitly state when NOT to use it or name specific alternatives among the sibling tools, such as when to use salesforce_manage_object instead for object-level changes.

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/usama-dtc/salesforce_mcp'

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