Skip to main content
Glama
mwhesse

Dataverse MCP Server

by mwhesse

Update Dataverse Option Set

update_dataverse_optionset

Modify Dataverse option sets by adding new choices, updating existing options, removing obsolete values, or changing display properties to maintain data consistency across all related columns.

Instructions

Updates an existing option set by modifying its properties and managing its options. Use this to add new choices, update existing ones, remove obsolete options, or change the option set's display name and description. Changes affect all columns using this option set.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
addOptionsNoNew options to add to the option set
descriptionNoNew description of the option set
displayNameNoNew display name for the option set
nameYesName of the option set to update
removeOptionsNoValues of options to remove from the option set
updateOptionsNoExisting options to update

Implementation Reference

  • Main handler function executing the tool: updates option set metadata, adds/removes/updates options via Dataverse API actions (InsertOptionValue, DeleteOptionValue, UpdateOptionValue).
    async (params) => {
      try {
        // Update basic properties if provided
        if (params.displayName || params.description) {
          // First, retrieve the current option set definition to get MetadataId
          const currentOptionSet = await client.getMetadata<OptionSetMetadata>(
            `GlobalOptionSetDefinitions(Name='${params.name}')`
          );
    
          // Create the updated option set definition by merging current with new values
          const updatedOptionSet: any = {
            ...currentOptionSet,
            "@odata.type": "Microsoft.Dynamics.CRM.OptionSetMetadata"
          };
    
          // Update only the specified properties
          if (params.displayName) {
            updatedOptionSet.DisplayName = createLocalizedLabel(params.displayName);
          }
          if (params.description) {
            updatedOptionSet.Description = createLocalizedLabel(params.description);
          }
    
          // Use PUT method with MetadataId as per Microsoft documentation
          // Only OptionSetMetadataBase properties can be updated this way
          await client.putMetadata(
            `GlobalOptionSetDefinitions(${currentOptionSet.MetadataId})`,
            updatedOptionSet,
            {
              'MSCRM.MergeLabels': 'true'
            }
          );
        }
    
        // Add new options using InsertOptionValue action
        if (params.addOptions && params.addOptions.length > 0) {
          for (const option of params.addOptions) {
            const insertOptionData = {
              OptionSetName: params.name,
              Value: option.value,
              Label: createLocalizedLabel(option.label),
              Description: option.description ? createLocalizedLabel(option.description) : undefined,
              Color: option.color
            };
    
            await client.callAction("InsertOptionValue", insertOptionData);
          }
        }
    
        // Remove options using DeleteOptionValue action
        if (params.removeOptions && params.removeOptions.length > 0) {
          for (const optionValue of params.removeOptions) {
            const deleteOptionData = {
              OptionSetName: params.name,
              Value: optionValue
            };
    
            await client.callAction("DeleteOptionValue", deleteOptionData);
          }
        }
    
        // Update existing options using UpdateOptionValue action
        if (params.updateOptions && params.updateOptions.length > 0) {
          for (const option of params.updateOptions) {
            const updateOptionData: any = {
              OptionSetName: params.name,
              Value: option.value,
              MergeLabels: true  // Required parameter for UpdateOptionValue action
            };
    
            // Only include properties that are being updated
            if (option.label) {
              updateOptionData.Label = createLocalizedLabel(option.label);
            }
            if (option.description) {
              updateOptionData.Description = createLocalizedLabel(option.description);
            }
            if (option.color) {
              updateOptionData.Color = option.color;
            }
    
            await client.callAction("UpdateOptionValue", updateOptionData);
          }
        }
    
        let message = `Successfully updated option set '${params.name}'.`;
        if (params.addOptions?.length) {
          message += ` Added ${params.addOptions.length} options.`;
        }
        if (params.updateOptions?.length) {
          message += ` Updated ${params.updateOptions.length} options.`;
        }
        if (params.removeOptions?.length) {
          message += ` Removed ${params.removeOptions.length} options.`;
        }
    
        return {
          content: [
            {
              type: "text",
              text: message
            }
          ]
        };
      } catch (error) {
        return {
          content: [
            {
              type: "text",
              text: `Error updating option set: ${error instanceof Error ? error.message : 'Unknown error'}`
            }
          ],
          isError: true
        };
      }
    }
  • Zod input schema defining parameters for updating an option set: name, optional displayName/description, addOptions/updateOptions/removeOptions arrays.
    inputSchema: {
      name: z.string().describe("Name of the option set to update"),
      displayName: z.string().optional().describe("New display name for the option set"),
      description: z.string().optional().describe("New description of the option set"),
      addOptions: z.array(z.object({
        value: z.number().describe("Numeric value for the new option"),
        label: z.string().describe("Display label for the new option"),
        description: z.string().optional().describe("Description for the new option"),
        color: z.string().optional().describe("Color for the new option (hex format)")
      })).optional().describe("New options to add to the option set"),
      updateOptions: z.array(z.object({
        value: z.number().describe("Numeric value of the option to update"),
        label: z.string().optional().describe("New display label for the option"),
        description: z.string().optional().describe("New description for the option"),
        color: z.string().optional().describe("New color for the option (hex format)")
      })).optional().describe("Existing options to update"),
      removeOptions: z.array(z.number()).optional().describe("Values of options to remove from the option set")
    }
  • server.registerTool call within the exported updateOptionSetTool function, registering the tool with its schema and handler on the MCP server.
    server.registerTool(
      "update_dataverse_optionset",
      {
        title: "Update Dataverse Option Set",
        description: "Updates an existing option set by modifying its properties and managing its options. Use this to add new choices, update existing ones, remove obsolete options, or change the option set's display name and description. Changes affect all columns using this option set.",
        inputSchema: {
          name: z.string().describe("Name of the option set to update"),
          displayName: z.string().optional().describe("New display name for the option set"),
          description: z.string().optional().describe("New description of the option set"),
          addOptions: z.array(z.object({
            value: z.number().describe("Numeric value for the new option"),
            label: z.string().describe("Display label for the new option"),
            description: z.string().optional().describe("Description for the new option"),
            color: z.string().optional().describe("Color for the new option (hex format)")
          })).optional().describe("New options to add to the option set"),
          updateOptions: z.array(z.object({
            value: z.number().describe("Numeric value of the option to update"),
            label: z.string().optional().describe("New display label for the option"),
            description: z.string().optional().describe("New description for the option"),
            color: z.string().optional().describe("New color for the option (hex format)")
          })).optional().describe("Existing options to update"),
          removeOptions: z.array(z.number()).optional().describe("Values of options to remove from the option set")
        }
      },
      async (params) => {
        try {
          // Update basic properties if provided
          if (params.displayName || params.description) {
            // First, retrieve the current option set definition to get MetadataId
            const currentOptionSet = await client.getMetadata<OptionSetMetadata>(
              `GlobalOptionSetDefinitions(Name='${params.name}')`
            );
    
            // Create the updated option set definition by merging current with new values
            const updatedOptionSet: any = {
              ...currentOptionSet,
              "@odata.type": "Microsoft.Dynamics.CRM.OptionSetMetadata"
            };
    
            // Update only the specified properties
            if (params.displayName) {
              updatedOptionSet.DisplayName = createLocalizedLabel(params.displayName);
            }
            if (params.description) {
              updatedOptionSet.Description = createLocalizedLabel(params.description);
            }
    
            // Use PUT method with MetadataId as per Microsoft documentation
            // Only OptionSetMetadataBase properties can be updated this way
            await client.putMetadata(
              `GlobalOptionSetDefinitions(${currentOptionSet.MetadataId})`,
              updatedOptionSet,
              {
                'MSCRM.MergeLabels': 'true'
              }
            );
          }
    
          // Add new options using InsertOptionValue action
          if (params.addOptions && params.addOptions.length > 0) {
            for (const option of params.addOptions) {
              const insertOptionData = {
                OptionSetName: params.name,
                Value: option.value,
                Label: createLocalizedLabel(option.label),
                Description: option.description ? createLocalizedLabel(option.description) : undefined,
                Color: option.color
              };
    
              await client.callAction("InsertOptionValue", insertOptionData);
            }
          }
    
          // Remove options using DeleteOptionValue action
          if (params.removeOptions && params.removeOptions.length > 0) {
            for (const optionValue of params.removeOptions) {
              const deleteOptionData = {
                OptionSetName: params.name,
                Value: optionValue
              };
    
              await client.callAction("DeleteOptionValue", deleteOptionData);
            }
          }
    
          // Update existing options using UpdateOptionValue action
          if (params.updateOptions && params.updateOptions.length > 0) {
            for (const option of params.updateOptions) {
              const updateOptionData: any = {
                OptionSetName: params.name,
                Value: option.value,
                MergeLabels: true  // Required parameter for UpdateOptionValue action
              };
    
              // Only include properties that are being updated
              if (option.label) {
                updateOptionData.Label = createLocalizedLabel(option.label);
              }
              if (option.description) {
                updateOptionData.Description = createLocalizedLabel(option.description);
              }
              if (option.color) {
                updateOptionData.Color = option.color;
              }
    
              await client.callAction("UpdateOptionValue", updateOptionData);
            }
          }
    
          let message = `Successfully updated option set '${params.name}'.`;
          if (params.addOptions?.length) {
            message += ` Added ${params.addOptions.length} options.`;
          }
          if (params.updateOptions?.length) {
            message += ` Updated ${params.updateOptions.length} options.`;
          }
          if (params.removeOptions?.length) {
            message += ` Removed ${params.removeOptions.length} options.`;
          }
    
          return {
            content: [
              {
                type: "text",
                text: message
              }
            ]
          };
        } catch (error) {
          return {
            content: [
              {
                type: "text",
                text: `Error updating option set: ${error instanceof Error ? error.message : 'Unknown error'}`
              }
            ],
            isError: true
          };
        }
      }
    );
  • src/index.ts:161-161 (registration)
    Top-level call to updateOptionSetTool registration helper in the main server initialization file.
    updateOptionSetTool(server, dataverseClient);
  • Helper function to create standardized LocalizedLabel objects used in option set metadata updates.
    function createLocalizedLabel(text: string, languageCode: number = 1033): LocalizedLabel {
      return {
        LocalizedLabels: [
          {
            Label: text,
            LanguageCode: languageCode,
            IsManaged: false,
            MetadataId: "00000000-0000-0000-0000-000000000000"
          }
        ],
        UserLocalizedLabel: {
          Label: text,
          LanguageCode: languageCode,
          IsManaged: false,
          MetadataId: "00000000-0000-0000-0000-000000000000"
        }
      };
Behavior3/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 does well by stating this is an update operation ('Updates an existing option set') and revealing an important behavioral consequence ('Changes affect all columns using this option set'). However, it doesn't mention permission requirements, whether changes are reversible, error conditions, or what the response looks like (especially important since there's no output schema).

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 perfectly structured with two sentences: the first states the core purpose, and the second provides usage guidance and important behavioral context. Every word earns its place, with no redundancy or unnecessary elaboration. It's front-loaded with the essential information.

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

Completeness3/5

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

For a mutation tool with 6 parameters, 100% schema coverage, but no annotations and no output schema, the description does an adequate job. It clearly states the purpose, provides usage guidance, and reveals an important behavioral consequence. However, it doesn't address permission requirements, error handling, or response format, which would be valuable given the tool's complexity and mutation nature.

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 has 100% description coverage, so the baseline is 3. The description adds some value by mentioning that properties can be modified and options can be managed, which aligns with the parameter structure (displayName, description, addOptions, updateOptions, removeOptions). However, it doesn't provide additional semantic context beyond what's already in the schema descriptions.

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 verb ('Updates') and resource ('an existing option set'), specifies what properties are modified ('properties and managing its options'), and distinguishes this tool from its sibling 'create_dataverse_optionset' by focusing on updates rather than creation. It provides specific examples of actions like adding new choices, updating existing ones, removing obsolete options, and changing display name and description.

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 ('Use this to add new choices, update existing ones, remove obsolete options, or change the option set's display name and description'), which implicitly distinguishes it from creation and deletion tools. However, it doesn't explicitly mention when NOT to use it (e.g., for creating new option sets or deleting entire option sets) or name specific alternative tools for those scenarios.

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/mwhesse/mcp-dataverse'

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