Skip to main content
Glama

datatype-update

Destructive

Create or update custom data types including structs, collections, and domain types for connectors and business objects in the Simplifier platform.

Instructions

#Create or update custom data types

Custom datatypes can be either

  • a struct type, which requires the definition of fields and their types (parameter "fields")

  • a collection type, which requires a datatype for its elements (parameter "collectionDatatype")

  • a domain type, which requires a parent type it is derived from (parameter "derivedFrom") These are mutually exclusive, so only specify exactly one of the three parameters.

In these parameters, referenced datatypes are specified by name. If it isn't a global datatype, the name must be prefixed with the namespace, separated with a slash.

Datatypes for connectors should be in the namespace "con/$name_of_connector", those for business objects in "bo/$name_of_bo".

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
qualifiedNameYes
descriptionNo
derivedFromNo
collectionDatatypeNo
fieldsNo
tagsYes
projectAssignmentsNo

Implementation Reference

  • The asynchronous handler function that implements the core logic of the 'datatype-update' tool. It processes input parameters, determines the datatype category, resolves namespaces and fields, constructs the SimplifierDataTypeUpdate object, checks if the datatype exists, and calls createDataType or updateDataType accordingly.
    }, async ({ qualifiedName: qualifiedName, description, derivedFrom, collectionDatatype, fields, tags, projectAssignments }) => {
      return wrapToolResult(`create or update data type ${qualifiedName}`, async () => {
    
        const { name: newTypeName, namespace: newTypeNamespace } = splitNamespace(qualifiedName);
        const category = determineCategory(fields, derivedFrom, collectionDatatype)
        if (category === 'base') {
          throw new Error("creating base types is not allowed")
        }
    
        const { name: derivedFromName, namespace: derivedFromNamespace } = derivedFrom ? splitNamespace(derivedFrom) : { name: undefined, namespace: undefined };
        const { name: collectionDtName, namespace: collectionDtNamespace } = collectionDatatype ? splitNamespace(collectionDatatype) : { name: undefined, namespace: undefined };
    
        const resolvedFields: SimplifierDataTypeFieldUpdate[] | undefined = fields?.map(f => {
          const { name: dtName, namespace: dtNamespace } = splitNamespace(f.dataType);
          return {
            name: f.name,
            dtName: dtName,
            dtNameSpace: dtNamespace,
            optional: f.optional,
            description: f.description,
          }
        })
    
        const data: SimplifierDataTypeUpdate = {
          name: newTypeName,
          nameSpace: newTypeNamespace,
          category: category,
          derivedFrom: derivedFromName,
          derivedFromNS: derivedFromNamespace,
          collDtName: collectionDtName,
          collDtNS: collectionDtNamespace,
          isStruct: category === 'struct',
          fields: resolvedFields || [],
          description: description,
          properties: [],
          editable: true,
          tags: tags || [],
          assignedProjects: projectAssignments || { projectsBefore: [], projectsAfterChange: [] },
        }
    
        const trackingKey = trackingToolPrefix + toolNameDatatypeUpdate
        let oExisting: any;
        try { oExisting = await simplifier.getSingleDataType(newTypeName, newTypeNamespace, trackingKey) } catch {}
        if (oExisting?.id) {
          return simplifier.updateDataType(data);
        } else {
          return simplifier.createDataType(data);
        }
      })
    });
  • Zod input schema defining parameters for 'datatype-update': qualifiedName (required), description, derivedFrom, collectionDatatype, fields (array of field objects), tags, and projectAssignments.
    {
      qualifiedName: z.string(),
      description: z.string().optional().default(""),
      derivedFrom: z.string().optional(),
      collectionDatatype: z.string().optional(),
      fields: z.array(z.object({
        name: z.string(),
        optional: z.boolean(),
        description: z.string().optional(),
        dataType: z.string(),
      })).optional(),
      tags: z.array(z.string()),
      projectAssignments: z.object({
        projectsBefore: z.array(z.string()),
        projectsAfterChange: z.array(z.string()),
      }).optional()
    },
  • Tool registration using McpServer.tool() for 'datatype-update', specifying name, description, input schema, hints, and inline handler function.
    const toolNameDatatypeUpdate = "datatype-update"
    server.tool(toolNameDatatypeUpdate,
      datatypeUpdateDescription,
      {
        qualifiedName: z.string(),
        description: z.string().optional().default(""),
        derivedFrom: z.string().optional(),
        collectionDatatype: z.string().optional(),
        fields: z.array(z.object({
          name: z.string(),
          optional: z.boolean(),
          description: z.string().optional(),
          dataType: z.string(),
        })).optional(),
        tags: z.array(z.string()),
        projectAssignments: z.object({
          projectsBefore: z.array(z.string()),
          projectsAfterChange: z.array(z.string()),
        }).optional()
      },
      {
        title: "Create or update a Data Type",
        readOnlyHint: false,
        destructiveHint: true,
        idempotentHint: false,
        openWorldHint: true
      }, async ({ qualifiedName: qualifiedName, description, derivedFrom, collectionDatatype, fields, tags, projectAssignments }) => {
        return wrapToolResult(`create or update data type ${qualifiedName}`, async () => {
    
          const { name: newTypeName, namespace: newTypeNamespace } = splitNamespace(qualifiedName);
          const category = determineCategory(fields, derivedFrom, collectionDatatype)
          if (category === 'base') {
            throw new Error("creating base types is not allowed")
          }
    
          const { name: derivedFromName, namespace: derivedFromNamespace } = derivedFrom ? splitNamespace(derivedFrom) : { name: undefined, namespace: undefined };
          const { name: collectionDtName, namespace: collectionDtNamespace } = collectionDatatype ? splitNamespace(collectionDatatype) : { name: undefined, namespace: undefined };
    
          const resolvedFields: SimplifierDataTypeFieldUpdate[] | undefined = fields?.map(f => {
            const { name: dtName, namespace: dtNamespace } = splitNamespace(f.dataType);
            return {
              name: f.name,
              dtName: dtName,
              dtNameSpace: dtNamespace,
              optional: f.optional,
              description: f.description,
            }
          })
    
          const data: SimplifierDataTypeUpdate = {
            name: newTypeName,
            nameSpace: newTypeNamespace,
            category: category,
            derivedFrom: derivedFromName,
            derivedFromNS: derivedFromNamespace,
            collDtName: collectionDtName,
            collDtNS: collectionDtNamespace,
            isStruct: category === 'struct',
            fields: resolvedFields || [],
            description: description,
            properties: [],
            editable: true,
            tags: tags || [],
            assignedProjects: projectAssignments || { projectsBefore: [], projectsAfterChange: [] },
          }
    
          const trackingKey = trackingToolPrefix + toolNameDatatypeUpdate
          let oExisting: any;
          try { oExisting = await simplifier.getSingleDataType(newTypeName, newTypeNamespace, trackingKey) } catch {}
          if (oExisting?.id) {
            return simplifier.updateDataType(data);
          } else {
            return simplifier.createDataType(data);
          }
        })
      });
  • Helper function determineCategory that classifies the datatype as 'struct', 'domain', 'collection', or 'base' based on the presence of fields, derivedFrom, and collectionDatatype parameters.
    const determineCategory = (
      fields: any[] | undefined,
      derivedFrom: string | undefined,
      collectionDatatype: string | undefined
    ): SimplifierDataTypeCategory => {
      const nonEmpty = (x: { length: number } | undefined) => (x?.length || 0) > 0
    
      const isStruct = nonEmpty(fields) && !derivedFrom && !collectionDatatype
      const isBase = !isStruct && !derivedFrom && !collectionDatatype
      const isDomain = !isStruct && nonEmpty(derivedFrom) && !collectionDatatype
      const isCollection = !isStruct && !derivedFrom && nonEmpty(collectionDatatype)
      if (isStruct) return 'struct';
      else if (isBase) return 'base'
      else if (isDomain) return 'domain'
      else if (isCollection) return 'collection';
      else throw new Error("Data type must either be a struct (have fields), a domain type (be derived from another type), a collection (with a collectionDatatype), or a base type (none of the above). Combinations are not allowed.")
    
    }
  • Helper function splitNamespace that parses a qualified name into namespace and name components, splitting on the last '/'.
    const splitNamespace = (qualifiedName: string): { namespace: string | undefined, name: string } => {
      const nameStart = qualifiedName.lastIndexOf('/')
      const namespace = nameStart > 0 ? qualifiedName.substring(0, nameStart) : undefined
      const name = qualifiedName.substring(nameStart + 1)
      return { namespace, name }
    }
  • Top-level registration in tools index that invokes registerServerDatatypeTools, thereby registering the 'datatype-update' tool among others.
    registerServerDatatypeTools(server, simplifier)
Behavior4/5

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

The description adds valuable behavioral context beyond annotations: it explains the mutually exclusive nature of three key parameters (fields, collectionDatatype, derivedFrom) and namespace formatting rules. While annotations already indicate this is a destructive, non-idempotent write operation (destructiveHint: true, idempotentHint: false), the description provides specific implementation details about datatype creation logic.

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 clear bullet points explaining the three datatype categories, followed by concise explanations of namespace conventions. Every sentence provides essential information with zero wasted words, making it easy to scan and understand.

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 tool with 7 parameters, nested objects, no output schema, and destructive annotations, the description does well covering the core datatype creation logic and parameter relationships. However, it doesn't explain the purpose of other parameters like tags, projectAssignments, or the qualifiedName format, leaving some gaps in understanding the full tool scope.

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

Parameters5/5

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

With 0% schema description coverage, the description carries the full burden of explaining parameters. It successfully explains the purpose and relationships of three critical parameters (fields, collectionDatatype, derivedFrom), their mutual exclusivity, and namespace formatting requirements for referenced datatypes. This adds substantial meaning beyond the bare schema.

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 explicitly states the tool's purpose as 'Create or update custom data types' with specific details about the three mutually exclusive datatype categories (struct, collection, domain). It clearly distinguishes this tool from its sibling 'datatype-delete' by focusing on creation/update rather than deletion.

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 about when to use specific parameters (mutually exclusive options for struct, collection, or domain types) and namespace conventions for connectors and business objects. However, it doesn't explicitly state when to use this tool versus alternatives like 'businessobject-update' or 'connector-update' which might handle related functionality.

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/simplifier-ag/simplifier-mcp'

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