Skip to main content
Glama

update_product

Modifies product details on Printify by updating the title, description, variants, and print areas using the provided product ID. Enables precise product management and customization within the Print-on-Demand platform.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
descriptionNoProduct description
printAreasNoPrint areas for the product
productIdYesProduct ID
titleNoProduct title
variantsNoProduct variants

Implementation Reference

  • src/index.ts:303-349 (registration)
    MCP tool registration for 'update_product', including inline Zod input schema validation and handler function that delegates to the printify-products service.
    server.tool(
      "update_product",
      {
        productId: z.string().describe("Product ID"),
        title: z.string().optional().describe("Product title"),
        description: z.string().optional().describe("Product description"),
        variants: z.array(z.object({
          variantId: z.number().describe("Variant ID"),
          price: z.number().describe("Price in cents (e.g., 1999 for $19.99)"),
          isEnabled: z.boolean().optional().describe("Whether the variant is enabled")
        })).optional().describe("Product variants"),
        printAreas: z.record(z.string(), z.object({
          position: z.string().describe("Print position (e.g., 'front', 'back')"),
          imageId: z.string().describe("Image ID from Printify uploads")
        })).optional().describe("Print areas for the product")
      },
      async ({ productId, title, description, variants, printAreas }): Promise<{ content: any[], isError?: boolean }> => {
        // Import the printify products service
        const { updateProduct } = await import('./services/printify-products.js');
    
        // Check if client is initialized
        if (!printifyClient) {
          return {
            content: [{
              type: "text",
              text: "Printify API client is not initialized. The PRINTIFY_API_KEY environment variable may not be set."
            }],
            isError: true
          };
        }
    
        // Call the service
        const result = await updateProduct(printifyClient, productId, {
          title,
          description,
          variants,
          printAreas
        });
    
        // Return the result
        if (result.success) {
          return result.response as { content: any[], isError?: boolean };
        } else {
          return result.errorResponse as { content: any[], isError: boolean };
        }
      }
    );
  • MCP handler function for update_product tool. Validates client initialization and calls the service layer updateProduct function.
    async ({ productId, title, description, variants, printAreas }): Promise<{ content: any[], isError?: boolean }> => {
      // Import the printify products service
      const { updateProduct } = await import('./services/printify-products.js');
    
      // Check if client is initialized
      if (!printifyClient) {
        return {
          content: [{
            type: "text",
            text: "Printify API client is not initialized. The PRINTIFY_API_KEY environment variable may not be set."
          }],
          isError: true
        };
      }
    
      // Call the service
      const result = await updateProduct(printifyClient, productId, {
        title,
        description,
        variants,
        printAreas
      });
    
      // Return the result
      if (result.success) {
        return result.response as { content: any[], isError?: boolean };
      } else {
        return result.errorResponse as { content: any[], isError: boolean };
      }
    }
  • Zod schema for input parameters of the update_product tool: required productId, optional title, description, variants array, and printAreas record.
      productId: z.string().describe("Product ID"),
      title: z.string().optional().describe("Product title"),
      description: z.string().optional().describe("Product description"),
      variants: z.array(z.object({
        variantId: z.number().describe("Variant ID"),
        price: z.number().describe("Price in cents (e.g., 1999 for $19.99)"),
        isEnabled: z.boolean().optional().describe("Whether the variant is enabled")
      })).optional().describe("Product variants"),
      printAreas: z.record(z.string(), z.object({
        position: z.string().describe("Print position (e.g., 'front', 'back')"),
        imageId: z.string().describe("Image ID from Printify uploads")
      })).optional().describe("Print areas for the product")
    },
  • Service helper function updateProduct that performs shop validation, calls PrintifyAPI.updateProduct, and returns formatted success/error responses.
    export async function updateProduct(
      printifyClient: PrintifyAPI,
      productId: string,
      updateData: {
        title?: string;
        description?: string;
        variants?: Array<{
          variantId: number;
          price: number;
          isEnabled?: boolean;
        }>;
        printAreas?: Record<string, {
          position: string;
          imageId: string;
        }>;
      }
    ) {
      try {
        // Validate shop is selected
        const currentShop = printifyClient.getCurrentShop();
        if (!currentShop) {
          throw new Error('No shop is currently selected. Use the list-shops and switch-shop tools to select a shop.');
        }
    
        // Update product
        const product = await printifyClient.updateProduct(productId, updateData);
    
        return {
          success: true,
          product,
          response: formatSuccessResponse(
            'Product Updated Successfully',
            {
              ProductId: productId,
              Title: updateData.title || 'Not updated',
              Shop: currentShop
            },
            `You may need to publish the changes using the publish-product tool.`
          )
        };
      } catch (error: any) {
        console.error('Error updating product:', error);
    
        return {
          success: false,
          error,
          errorResponse: formatErrorResponse(
            error,
            'Update Product',
            {
              ProductId: productId,
              UpdateData: updateData,
              Shop: printifyClient.getCurrentShop()
            },
            [
              'Check that the product ID is valid',
              'Check that the variant IDs are valid',
              'Ensure your Printify account is properly connected',
              'Make sure you have selected a shop'
            ]
          )
        };
      }
    }
  • Low-level PrintifyAPI class method that formats the update data (handling print_areas conversion to Printify SDK format) and calls client.products.updateOne.
    async updateProduct(productId: string, productData: any) {
      if (!this.shopId) {
        throw new Error('Shop ID is not set. Call setShopId() first.');
      }
    
      try {
        // Format the product data if it contains print_areas
        if (productData.print_areas || productData.printAreas) {
          const formattedData = { ...productData };
          const printAreasData = formattedData.print_areas || formattedData.printAreas;
    
          // If print_areas is provided, format it correctly
          if (printAreasData) {
            // Get the current product to get variant IDs if not provided
            let variantIds: number[] = [];
    
            if (formattedData.variants && Array.isArray(formattedData.variants)) {
              // Use the variants from the update data
              variantIds = formattedData.variants.map((v: any) => parseInt(v.id || v.variantId));
            } else {
              // Get the current product to get its variant IDs
              try {
                const currentProduct = await this.client.products.getOne(productId);
                variantIds = currentProduct.variants
                  .filter((v: any) => v.is_enabled)
                  .map((v: any) => v.id);
              } catch (error) {
                console.error(`Error fetching current product ${productId}:`, error);
                // Continue with empty variant IDs
              }
            }
    
            // Create a print area entry with all variants
            const printAreaEntry: any = {
              variant_ids: variantIds,
              placeholders: []
            };
    
            // Add placeholders for each position (front, back, etc.)
            for (const key in printAreasData) {
              const area = printAreasData[key];
              printAreaEntry.placeholders.push({
                position: area.position,
                images: [
                  {
                    id: area.image_id || area.imageId,
                    x: 0.5,
                    y: 0.5,
                    scale: 1,
                    angle: 0
                  }
                ]
              });
            }
    
            // Replace the print_areas with the correctly formatted version
            formattedData.print_areas = [printAreaEntry];
    
            // Remove the printAreas property if it exists
            if (formattedData.printAreas) {
              delete formattedData.printAreas;
            }
          }
    
          console.log(`Updating product ${productId} with formatted data:`, JSON.stringify(formattedData, null, 2));
          return await this.client.products.updateOne(productId, formattedData);
        } else {
          // If no print_areas, just pass the data as is
          return await this.client.products.updateOne(productId, productData);
        }
      } catch (error) {
        console.error(`Error updating product ${productId}:`, error);
        throw this.enhanceError(error, productData);
      }
    }

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/TSavo/printify-mcp'

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