upload_product_image
Attach an image to a product by providing a public URL. Shopify fetches and hosts the image on its CDN, adding it without replacing existing images.
Instructions
Attach an image to an existing product by URL. Shopify fetches the URL server-side and hosts the file on its CDN — the URL must be publicly reachable from Shopify's network. Multiple calls add multiple images; this tool does not replace existing images. Use the bridge tools (generate_product_image, refine_product_image) instead when you want the image generated by ComfyUI rather than provided as a URL.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| product_id | Yes | Product GID or numeric ID | |
| image_url | Yes | Public image URL to attach | |
| alt_text | No |
Implementation Reference
- src/tools/products.ts:293-305 (handler)The handler for the 'upload_product_image' tool. Takes product_id, image_url, and optional alt_text, converts product_id to GID, then calls attachImages() to upload the image via Shopify's API.
async (args) => { const productId = toGid(args.product_id, "Product"); const result = await attachImages(client, productId, [args.image_url], args.alt_text); return { content: [ { type: "text" as const, text: `Attached image to ${productId}: ${result.map((m) => m.id).join(", ")}`, }, ], }; }, ); - src/tools/products.ts:152-156 (schema)Zod schema for upload_product_image: product_id (string), image_url (string/url), alt_text (optional string).
const uploadProductImageSchema = { product_id: z.string().describe("Product GID or numeric ID"), image_url: z.string().url().describe("Public image URL to attach"), alt_text: z.string().optional(), }; - src/tools/products.ts:289-305 (registration)Registration of 'upload_product_image' tool via server.tool() inside registerProductTools(), with description and schema.
server.tool( "upload_product_image", "Attach an image to an existing product by URL. Shopify fetches the URL server-side and hosts the file on its CDN — the URL must be publicly reachable from Shopify's network. Multiple calls add multiple images; this tool does not replace existing images. Use the bridge tools (generate_product_image, refine_product_image) instead when you want the image generated by ComfyUI rather than provided as a URL.", uploadProductImageSchema, async (args) => { const productId = toGid(args.product_id, "Product"); const result = await attachImages(client, productId, [args.image_url], args.alt_text); return { content: [ { type: "text" as const, text: `Attached image to ${productId}: ${result.map((m) => m.id).join(", ")}`, }, ], }; }, ); - src/tools/products.ts:308-331 (helper)Helper function attachImages() that executes the GraphQL mutation to attach image(s) to a product. Uses CREATE_MEDIA_MUTATION.
export async function attachImages( client: ShopifyClient, productId: string, imageUrls: string[], altText?: string, ): Promise<Array<{ id: string }>> { const data = await client.graphql<{ productCreateMedia: { media: Array<{ id: string } | null>; mediaUserErrors: ShopifyUserError[]; }; }>(CREATE_MEDIA_MUTATION, { productId, media: imageUrls.map((url) => ({ originalSource: url, mediaContentType: "IMAGE", alt: altText, })), }); throwIfUserErrors(data.productCreateMedia.mediaUserErrors, "productCreateMedia"); return data.productCreateMedia.media.filter( (m): m is { id: string } => m !== null, ); } - src/tools/products.ts:98-110 (helper)GraphQL mutation CREATE_MEDIA_MUTATION used by attachImages to create media (images) on a product.
const CREATE_MEDIA_MUTATION = /* GraphQL */ ` mutation ProductCreateMedia($productId: ID!, $media: [CreateMediaInput!]!) { productCreateMedia(productId: $productId, media: $media) { media { ... on MediaImage { id image { url altText } } } mediaUserErrors { field message } } } `;