publish_product
Publish a Printify product to your store using its product ID, with control over which details (title, description, images, variants, tags) to include.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| productId | Yes | Product ID | |
| publishDetails | No | Publish details |
Implementation Reference
- The main handler function 'publishProduct' that executes the tool logic. It validates the shop is selected, calls the printify client to publish the product, and returns a formatted success or error response.
export async function publishProduct( printifyClient: PrintifyAPI, productId: string, publishDetails?: { title?: boolean; description?: boolean; images?: boolean; variants?: boolean; tags?: boolean; } ) { 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.'); } // Publish product const result = await printifyClient.publishProduct(productId, publishDetails); return { success: true, result, response: formatSuccessResponse( 'Product Published Successfully', { ProductId: productId, Shop: currentShop } ) }; } catch (error: any) { console.error('Error publishing product:', error); return { success: false, error, errorResponse: formatErrorResponse( error, 'Publish Product', { ProductId: productId, PublishDetails: publishDetails, Shop: printifyClient.getCurrentShop() }, [ 'Check that the product ID is valid', 'Ensure your Printify account is properly connected', 'Make sure you have selected a shop' ] ) }; } } - src/index.ts:384-422 (registration)The tool registration using server.tool('publish_product', ...) with Zod schema for inputs (productId and optional publishDetails) and the handler that imports and calls the publishProduct service.
// Publish product tool server.tool( "publish_product", { productId: z.string().describe("Product ID"), publishDetails: z.object({ title: z.boolean().optional().default(true).describe("Publish title"), description: z.boolean().optional().default(true).describe("Publish description"), images: z.boolean().optional().default(true).describe("Publish images"), variants: z.boolean().optional().default(true).describe("Publish variants"), tags: z.boolean().optional().default(true).describe("Publish tags") }).optional().describe("Publish details") }, async ({ productId, publishDetails }): Promise<{ content: any[], isError?: boolean }> => { // Import the printify products service const { publishProduct } = 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 publishProduct(printifyClient, productId, publishDetails); // Return the result if (result.success) { return result.response as { content: any[], isError?: boolean }; } else { return result.errorResponse as { content: any[], isError: boolean }; } } ); - src/index.ts:387-395 (schema)Zod schema definition for the publish_product tool inputs: productId (string) and optional publishDetails object with boolean fields for title, description, images, variants, and tags.
{ productId: z.string().describe("Product ID"), publishDetails: z.object({ title: z.boolean().optional().default(true).describe("Publish title"), description: z.boolean().optional().default(true).describe("Publish description"), images: z.boolean().optional().default(true).describe("Publish images"), variants: z.boolean().optional().default(true).describe("Publish variants"), tags: z.boolean().optional().default(true).describe("Publish tags") }).optional().describe("Publish details") - src/printify-api.ts:390-402 (helper)The PrintifyAPI client method 'publishProduct' that calls the Printify SDK's products.publishOne method to actually publish the product via the API.
async publishProduct(productId: string, publishData: any) { if (!this.shopId) { throw new Error('Shop ID is not set. Call setShopId() first.'); } try { // Use the products.publishOne method with the product ID and publish data return await this.client.products.publishOne(productId, publishData); } catch (error) { console.error(`Error publishing product ${productId}:`, error); throw this.enhanceError(error, publishData); } } - src/utils/error-handler.ts:1-107 (helper)Helper utilities formatErrorResponse and formatSuccessResponse used by the publishProduct handler to format output for the MCP response.
/** * Error handling utilities for Printify MCP */ /** * Format an error response for tool output */ export function formatErrorResponse( error: any, step: string, context: Record<string, any> = {}, tips: string[] = [] ) { // Get error details const errorType = error.constructor.name; const errorMessage = error.message || 'Unknown error'; const errorStack = error.stack ? error.stack.split('\n').slice(0, 3).join('\n') : 'Not available'; // Format the error message let text = `ā **Error in ${step}**\n\n`; // Add context information Object.entries(context).forEach(([key, value]) => { if (typeof value === 'string' && value.includes('"')) { text += `- **${key}**: ${value}\n`; } else if (typeof value === 'object') { text += `- **${key}**: ${JSON.stringify(value)}\n`; } else { text += `- **${key}**: "${value}"\n`; } }); text += `- **Error**: ${errorMessage}\n\n`; // Add detailed diagnostic information text += `=== DETAILED DIAGNOSTIC INFORMATION ===\n\n`; text += `- **Error Type**: ${errorType}\n`; text += `- **Error Stack**: ${errorStack}\n`; // Add additional context details Object.entries(context).forEach(([key, value]) => { if (key !== 'Prompt' && key !== 'Model' && key !== 'Error') { if (typeof value === 'object' && value !== null) { text += `- **${key}**: ${JSON.stringify(value, null, 2)}\n`; } else if (value !== undefined && value !== null) { text += `- **${key}**: ${value}\n`; } } }); // Add system information text += `- **Current Working Directory**: ${process.cwd()}\n`; text += `- **Node.js Version**: ${process.version}\n`; text += `- **Platform**: ${process.platform}\n\n`; // Add API response data if available if (error.response) { text += `- **API Response Status**: ${error.response.status}\n`; text += `- **API Response Data**: ${JSON.stringify(error.response.data, null, 2)}\n\n`; } // Add tips if provided if (tips.length > 0) { text += `\nš Please try again with a different prompt or parameters.\n\n`; text += 'š” **Tips**:\n'; tips.forEach(tip => { text += `⢠${tip}\n`; }); } return { content: [{ type: "text", text }], isError: true }; } /** * Format a success response for tool output */ export function formatSuccessResponse( title: string, data: Record<string, any> = {}, additionalText: string = '' ) { let text = `ā **${title}**\n\n`; // Add data information Object.entries(data).forEach(([key, value]) => { if (typeof value === 'string' && value.includes('"')) { text += `- **${key}**: ${value}\n`; } else if (typeof value === 'object') { text += `- **${key}**: ${JSON.stringify(value)}\n`; } else { text += `- **${key}**: "${value}"\n`; } }); // Add additional text if provided if (additionalText) { text += `\n${additionalText}`; } return { content: [{ type: "text", text }] }; }