Skip to main content
Glama

create_variants

Create multiple product variants by specifying full option combinations, pricing, and initial stock per location. Remove the default placeholder variant when adding the first real variant.

Instructions

Create one or more variants on an existing product. Each variant's optionValues must cover EVERY option declared on the product (Size + Color + Material if there are 3 options) — partial coverage is rejected. New products from create_product start with a single hidden 'Default Title' variant; when adding the first real variants, pass strategy='REMOVE_STANDALONE_VARIANT' so Shopify replaces the placeholder rather than leaving it. inventoryQuantities seeds initial stock per location at create time; for ongoing changes use set_inventory_quantity instead.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
productIdYesProduct GID.
variantsYes
strategyNoDEFAULT: add to existing variants. REMOVE_STANDALONE_VARIANT: replace the auto-created 'Default Title' variant (use on first real variant create).

Implementation Reference

  • The tool handler for 'create_variants'. Receives productId, variants (array of variantCreateSchema), and optional strategy. Calls the VARIANTS_BULK_CREATE_MUTATION GraphQL mutation and returns formatted results.
    server.tool(
      "create_variants",
      "Create one or more variants on an existing product. Each variant's optionValues must cover EVERY option declared on the product (Size + Color + Material if there are 3 options) — partial coverage is rejected. New products from create_product start with a single hidden 'Default Title' variant; when adding the first real variants, pass strategy='REMOVE_STANDALONE_VARIANT' so Shopify replaces the placeholder rather than leaving it. inventoryQuantities seeds initial stock per location at create time; for ongoing changes use set_inventory_quantity instead.",
      createVariantsSchema,
      async (args) => {
        const data = await client.graphql<{
          productVariantsBulkCreate: {
            productVariants: VariantNode[];
            userErrors: ShopifyUserError[];
          };
        }>(VARIANTS_BULK_CREATE_MUTATION, {
          productId: args.productId,
          variants: args.variants,
          strategy: args.strategy,
        });
        throwIfUserErrors(
          data.productVariantsBulkCreate.userErrors,
          "productVariantsBulkCreate",
        );
        const created = data.productVariantsBulkCreate.productVariants;
        return {
          content: [
            {
              type: "text" as const,
              text: [
                `Created ${created.length} variant(s):`,
                ...created.map((v) => formatVariant(v)),
              ].join("\n"),
            },
          ],
        };
      },
    );
  • Input schema (createVariantsSchema) for the tool. productId (string), variants (array of variantCreateSchema with 1-100 items), strategy (optional enum: DEFAULT|REMOVE_STANDALONE_VARIANT).
    const createVariantsSchema = {
      productId: z.string().describe("Product GID."),
      variants: z.array(variantCreateSchema).min(1).max(100),
      strategy: z
        .enum(["DEFAULT", "REMOVE_STANDALONE_VARIANT"])
        .optional()
        .describe(
          "DEFAULT: add to existing variants. REMOVE_STANDALONE_VARIANT: replace the auto-created 'Default Title' variant (use on first real variant create).",
        ),
    };
  • The variantCreateSchema defining the shape of each variant in the variants array: optionValues, price, compareAtPrice, sku, barcode, taxable, inventoryPolicy, inventoryQuantities.
    const variantCreateSchema = z.object({
      optionValues: z
        .array(optionValueInputSchema)
        .describe(
          "One entry per product option. Shape must match the product's options (order-insensitive, matched by optionName).",
        ),
      price: z.string().describe("Variant price as decimal string, e.g. '19.99'."),
      compareAtPrice: z.string().optional(),
      sku: z.string().optional(),
      barcode: z.string().optional(),
      taxable: z.boolean().optional(),
      inventoryPolicy: z
        .enum(["DENY", "CONTINUE"])
        .optional()
        .describe(
          "Oversell policy: DENY blocks sales at 0 stock, CONTINUE allows backorder.",
        ),
      inventoryQuantities: z
        .array(inventoryQuantityInputSchema)
        .optional()
        .describe(
          "Initial stock per location. Only accepted on create — use set_inventory_quantity for subsequent updates.",
        ),
    });
  • The GraphQL mutation (VARIANTS_BULK_CREATE_MUTATION) used by the create_variants handler to perform the bulk create operation.
    const VARIANTS_BULK_CREATE_MUTATION = /* GraphQL */ `
      mutation VariantsBulkCreate(
        $productId: ID!
        $variants: [ProductVariantsBulkInput!]!
        $strategy: ProductVariantsBulkCreateStrategy
      ) {
        productVariantsBulkCreate(
          productId: $productId
          variants: $variants
          strategy: $strategy
        ) {
          productVariants {
            id
            title
            price
            sku
            selectedOptions { name value }
          }
          userErrors { field message }
        }
      }
    `;
  • src/server.ts:56-64 (registration)
    Registration of all variant tools (including create_variants) in the MCP server via registerVariantTools(s, shopify).
    const s = new McpServer({ name: "shopify-mcp", version: "0.1.0" });
    registerProductTools(s, shopify);
    registerOrderTools(s, shopify);
    registerInventoryTools(s, shopify);
    registerCustomerTools(s, shopify);
    registerMetafieldTools(s, shopify);
    registerDraftOrderTools(s, shopify);
    registerCollectionTools(s, shopify);
    registerVariantTools(s, shopify);
Behavior4/5

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

No annotations provided, so description carries full burden. It discloses that partial coverage of optionValues is rejected, new products start with a hidden default variant, and inventoryQuantities is only accepted on create. Could be improved by mentioning return type or error handling, but overall sufficient.

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?

Two information-dense sentences, front-loaded with main purpose. Every sentence adds necessary context without redundancy. Efficient and clear.

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?

Covers key behavioral constraints for a creation tool with nested parameters. Does not mention return value or error scenarios, which would improve completeness given no output schema. Otherwise, adequate for usage.

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

Parameters4/5

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

Schema description coverage is high (67%+). The description adds value beyond schema by clarifying the requirement for complete option coverage and explaining the strategy parameter in context of the default variant. Some optional parameters (compareAtPrice, barcode) lack schema descriptions, but the tool description does not address them, so a 4 is appropriate.

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?

Clearly states 'Create one or more variants on an existing product.' Identifies specific verb, resource, and scope (variant creation on existing product). Distinguishes from sibling tools like update_variants, delete_variants, and create_product.

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

Usage Guidelines5/5

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

Provides explicit when-to-use guidance: requires full option coverage, explains the default placeholder variant and when to use strategy='REMOVE_STANDALONE_VARIANT', and instructs to use set_inventory_quantity for ongoing inventory changes. Contrasts with sibling tool set_inventory_quantity.

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/miller-joe/shopify-mcp'

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