{"$schema":"https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json","name":"com.useproductify/productify","title":"Productify","description":"Create, write and publish Printify products from chat, after a preview you approve.","version":"2.0.0","websiteUrl":"https://www.useproductify.com/mcp","icons":[{"src":"https://www.useproductify.com/icon.png","mimeType":"image/png","sizes":["192x192"]}],"remotes":[{"type":"streamable-http","url":"https://www.useproductify.com/api/mcp"}],"serverInfo":{"name":"productify","title":"Productify","version":"2.0.0"},"authentication":{"required":true,"schemes":["oauth2"]},"tools":[{"name":"list_shops_and_templates","title":"List shops and templates","description":"Lists the seller's connected Printify shops (which one is selected) and the saved templates of the selected shop. A template is a saved product setup: product type, print provider, colors, sizes, placement and price. Call this first to get a templateId.","inputSchema":{"type":"object","$schema":"https://json-schema.org/draft/2020-12/schema","properties":{}},"annotations":{"readOnlyHint":true,"idempotentHint":true,"destructiveHint":false,"openWorldHint":false},"_meta":{"openai/toolInvocation/invoking":"Reading your shops","openai/toolInvocation/invoked":"Shops and templates ready"}},{"name":"stage_designs","title":"Add designs to an upload","description":"Adds the images the user attached (PNG or JPEG, up to 20 per call) to a new upload on a saved template in the selected shop: one proposed product per design. Each image is uploaded to Productify and to the seller's Printify media library. This tool creates no product in Printify; that is preview_create, or the seller in Productify at the reviewUrl. Designs must be print resolution. Images generated in ChatGPT are usually too small to print sharply; printWarnings names any that will print blurry. Optional titles, in the same order as files, name the products. Each call makes one upload on one template; to put one design on several products (a tee, a mug, a tote), call it once per template. The same designs on the same template again return the existing upload. Then Productify's writer starts the listings (description and tags, and the title unless one was given), in the background; get_review shows when each is written. If the shop has no listing voice yet, the answer is listings: needs_voice: ask the seller, call set_shop_voice, then write_listings. Files on the seller's own computer (a local path, as in Codex) cannot be read here: call get_upload_urls first and pass uploads instead of files.","inputSchema":{"type":"object","$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"templateId":{"type":"string","minLength":1,"maxLength":100,"description":"From list_shops_and_templates."},"files":{"maxItems":20,"type":"array","items":{"anyOf":[{"type":"object","properties":{"download_url":{"type":"string"},"file_id":{"type":"string"},"mime_type":{"type":"string"},"file_name":{"type":"string"}},"additionalProperties":{}},{"type":"string"}]}},"uploads":{"description":"From get_upload_urls, for files on the seller's computer, once each file is PUT.","maxItems":20,"type":"array","items":{"type":"object","properties":{"uploadId":{"type":"string","minLength":1,"maxLength":2000},"title":{"type":"string","maxLength":140}},"required":["uploadId"]}},"titles":{"maxItems":20,"type":"array","items":{"type":"string","maxLength":140}},"listings":{"description":"Default write. none stages only.","type":"string","enum":["write","none"]}},"required":["templateId"]},"annotations":{"readOnlyHint":false,"destructiveHint":false,"idempotentHint":true,"openWorldHint":true},"_meta":{"openai/fileParams":["files"],"openai/toolInvocation/invoking":"Uploading your designs","openai/toolInvocation/invoked":"Designs added"}},{"name":"get_upload_urls","title":"Get upload links for local files","description":"For designs that are files on the seller's computer (up to 20): returns a one-time upload URL per file. Give each file's name, size in bytes, type (image/png or image/jpeg) and SHA-256 (64 lowercase hex characters, e.g. from shasum -a 256). PUT each file's exact bytes to its uploadUrl with the headers given, then call stage_designs with uploads: the uploadIds. A file whose bytes differ from its SHA-256 is refused.","inputSchema":{"type":"object","$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"files":{"minItems":1,"maxItems":20,"type":"array","items":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":260},"size":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991},"type":{"type":"string","enum":["image/png","image/jpeg"]},"sha256":{"type":"string","minLength":64,"maxLength":64}},"required":["name","size","type","sha256"]}}},"required":["files"]},"annotations":{"readOnlyHint":false,"destructiveHint":false,"idempotentHint":false,"openWorldHint":false},"_meta":{"openai/toolInvocation/invoking":"Preparing uploads","openai/toolInvocation/invoked":"Upload links ready"}},{"name":"get_review","title":"Show the upload's products","description":"Shows the products an unfinished upload will create: title, file, variant count, price range, whether a listing is written, and print warnings. Defaults to the newest upload when batchId is omitted, and lists the shop's other unfinished uploads.","inputSchema":{"type":"object","$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"batchId":{"type":"string","maxLength":100}}},"annotations":{"readOnlyHint":true,"idempotentHint":true,"destructiveHint":false,"openWorldHint":true},"_meta":{"openai/toolInvocation/invoking":"Reading the upload","openai/toolInvocation/invoked":"Upload ready"}},{"name":"get_job_status","title":"Check a run's progress","description":"Reports the progress of a create, publish or edit run in the selected shop: status, how many are done, failed or need review. For a publish run it also checks Printify for how many the store has confirmed (live) and how many are still waiting; a store can take minutes. Defaults to the newest run when jobId is omitted.","inputSchema":{"type":"object","$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"jobId":{"type":"string","maxLength":100}}},"annotations":{"readOnlyHint":true,"idempotentHint":true,"destructiveHint":false,"openWorldHint":true},"_meta":{"ui":{"resourceUri":"ui://productify/cards-v1.html"},"ui/resourceUri":"ui://productify/cards-v1.html","openai/toolInvocation/invoking":"Checking progress","openai/toolInvocation/invoked":"Progress ready"}},{"name":"write_listings","title":"Write the upload's listings","description":"Starts Productify's writer on an unfinished upload (batchId, default the newest): title, description and tags for each product, in the shop's voice, following Etsy's rules. Runs in the background; get_review shows each listing once written. Pass skipVoice: true only when the seller chose not to set a voice.","inputSchema":{"type":"object","$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"batchId":{"type":"string","maxLength":100},"skipVoice":{"type":"boolean"}}},"annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":false,"openWorldHint":true},"_meta":{"openai/toolInvocation/invoking":"Starting the listings","openai/toolInvocation/invoked":"Listings started"}},{"name":"set_shop_voice","title":"Set the shop's listing voice","description":"Saves how the selected shop's listings should sound, which every later upload uses too. Only when the shop has none yet. voice: one to three ids from cool (Cool and understated), trendy (Trendy), nerdy (Nerdy), warm (Warm and personal), struggle (Inspires through the struggle), celebrate (Celebratory), playful (Playful), minimal (Minimal). note: the seller's own words about the voice, optional. story: a line or two about the shop, optional, saved only if the shop has no story yet. Use only what the seller said; never invent a voice or story.","inputSchema":{"type":"object","$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"voice":{"minItems":1,"maxItems":3,"type":"array","items":{"type":"string","maxLength":40}},"note":{"type":"string","maxLength":400},"story":{"type":"string","maxLength":600}},"required":["voice"]},"annotations":{"readOnlyHint":false,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false},"_meta":{"openai/toolInvocation/invoking":"Saving the voice","openai/toolInvocation/invoked":"Voice saved"}},{"name":"preview_create","title":"Preview creating products","description":"Shows exactly which products from the shop's unfinished uploads would be created in Printify, with prices and print warnings, and returns a confirmToken. Show the seller the list and ask them to confirm before calling create_products. Nothing is created by this tool. Up to 20 products. Pass batchId for one upload (default: the newest), or productIds from get_review to choose products, including from several uploads at once. Refuses while listings are still being written, and when listings are unwritten unless withoutListings is true (the seller chose to keep their own titles and description).","inputSchema":{"type":"object","$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"batchId":{"type":"string","maxLength":100},"productIds":{"maxItems":20,"type":"array","items":{"type":"string","maxLength":100}},"withoutListings":{"type":"boolean"}}},"annotations":{"readOnlyHint":true,"idempotentHint":true,"destructiveHint":false,"openWorldHint":true},"_meta":{"ui":{"resourceUri":"ui://productify/cards-v1.html"},"ui/resourceUri":"ui://productify/cards-v1.html","openai/toolInvocation/invoking":"Checking the upload","openai/toolInvocation/invoked":"Ready to confirm"}},{"name":"create_products","title":"Create products in Printify","description":"Creates the products the seller confirmed in Printify, in the selected shop and not yet published. Tell the seller they are synced to Printify, never call them drafts. Call only after preview_create and the seller's yes, passing shop, products (productId and title) and confirmToken exactly as preview_create returned them. Starts the run and returns at once; follow it with get_job_status. Does not publish.","inputSchema":{"type":"object","$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"shop":{"type":"string","maxLength":200,"description":"The shop title from preview_create."},"products":{"minItems":1,"maxItems":20,"type":"array","items":{"type":"object","properties":{"productId":{"type":"string","minLength":1,"maxLength":100},"title":{"type":"string","maxLength":200}},"required":["productId","title"]}},"withoutListings":{"type":"boolean"},"confirmToken":{"type":"string","minLength":1,"maxLength":100}},"required":["shop","products","confirmToken"]},"annotations":{"readOnlyHint":false,"destructiveHint":false,"idempotentHint":true,"openWorldHint":true},"_meta":{"ui":{"resourceUri":"ui://productify/cards-v1.html"},"ui/resourceUri":"ui://productify/cards-v1.html","openai/toolInvocation/invoking":"Creating products","openai/toolInvocation/invoked":"Creation started"}},{"name":"find_products","title":"Find products","description":"Finds products in the selected shop by words in the title, and by status (staged: in an upload, not created yet; draft: synced to Printify, not published; publishing; published; failed). Returns up to 20, newest first, with the productId the other tools take.","inputSchema":{"type":"object","$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"query":{"type":"string","maxLength":100},"status":{"type":"string","enum":["staged","draft","publishing","published","failed","all"]}}},"annotations":{"readOnlyHint":true,"idempotentHint":true,"destructiveHint":false,"openWorldHint":false},"_meta":{"openai/toolInvocation/invoking":"Finding products","openai/toolInvocation/invoked":"Products found"}},{"name":"preview_publish","title":"Preview publishing products","description":"Shows which products would be published from Printify to the shop's store, which are new listings and which update a live one, and returns a confirmToken. Defaults to the products the newest create run made; or pass jobId, or up to 20 productIds from find_products. Show the seller the list and ask them to confirm before calling publish_products. Nothing is published by this tool.","inputSchema":{"type":"object","$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"jobId":{"type":"string","maxLength":100},"productIds":{"maxItems":20,"type":"array","items":{"type":"string","maxLength":100}}}},"annotations":{"readOnlyHint":true,"idempotentHint":true,"destructiveHint":false,"openWorldHint":false},"_meta":{"ui":{"resourceUri":"ui://productify/cards-v1.html"},"ui/resourceUri":"ui://productify/cards-v1.html","openai/toolInvocation/invoking":"Checking what can be published","openai/toolInvocation/invoked":"Ready to confirm"}},{"name":"publish_products","title":"Publish products to the store","description":"Publishes the products the seller confirmed from Printify to the shop's store. Call only after preview_publish and the seller's yes, passing shop, products (productId and title) and confirmToken exactly as preview_publish returned them. Starts the run and returns at once; follow it with get_job_status. Republishing a live product replaces edits made to it in the store.","inputSchema":{"type":"object","$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"shop":{"type":"string","maxLength":200,"description":"The shop title from preview_publish."},"products":{"minItems":1,"maxItems":20,"type":"array","items":{"type":"object","properties":{"productId":{"type":"string","minLength":1,"maxLength":100},"title":{"type":"string","maxLength":200}},"required":["productId","title"]}},"confirmToken":{"type":"string","minLength":1,"maxLength":100}},"required":["shop","products","confirmToken"]},"annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":true,"openWorldHint":true},"_meta":{"ui":{"resourceUri":"ui://productify/cards-v1.html"},"ui/resourceUri":"ui://productify/cards-v1.html","openai/toolInvocation/invoking":"Publishing","openai/toolInvocation/invoked":"Publishing started"}},{"name":"preview_edit","title":"Preview product edits","description":"Checks changes to up to 10 products (title, description, tags, price) and shows each product's before and after, with a confirmToken. Works on products in an upload and products already in Printify. Tags follow Etsy's rules (13 tags, 20 characters); a price must be above Printify's cost for every variant. Show the seller each before and after and ask them to confirm before calling edit_products. Nothing changes until then.","inputSchema":{"type":"object","$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"edits":{"minItems":1,"maxItems":10,"type":"array","items":{"type":"object","properties":{"productId":{"type":"string","minLength":1,"maxLength":100},"title":{"type":"string","maxLength":200},"description":{"type":"string","maxLength":12000},"tags":{"maxItems":30,"type":"array","items":{"type":"string","maxLength":60}},"price":{"type":"object","properties":{"retail":{"description":"Retail price in dollars, the same for every size.","type":"number"},"profit":{"description":"Profit in dollars over each variant's Printify cost.","type":"number"},"markupPercent":{"description":"Percent over each variant's Printify cost.","type":"number"}}}},"required":["productId"]}}},"required":["edits"]},"annotations":{"readOnlyHint":true,"idempotentHint":true,"destructiveHint":false,"openWorldHint":true},"_meta":{"ui":{"resourceUri":"ui://productify/cards-v1.html"},"ui/resourceUri":"ui://productify/cards-v1.html","openai/toolInvocation/invoking":"Checking the changes","openai/toolInvocation/invoked":"Ready to confirm"}},{"name":"edit_products","title":"Edit products","description":"Applies the changes the seller confirmed. Call only after preview_edit and the seller's yes, passing shop, edits and confirmToken exactly as preview_edit returned them. Overwrites the title, description, tags or price given. A live product's store listing shows the change after its next publish.","inputSchema":{"type":"object","$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"shop":{"type":"string","maxLength":200,"description":"The shop title from preview_edit."},"edits":{"minItems":1,"maxItems":10,"type":"array","items":{"type":"object","properties":{"productId":{"type":"string","minLength":1,"maxLength":100},"title":{"type":"string","maxLength":200},"description":{"type":"string","maxLength":12000},"tags":{"maxItems":30,"type":"array","items":{"type":"string","maxLength":60}},"price":{"type":"object","properties":{"retail":{"description":"Retail price in dollars, the same for every size.","type":"number"},"profit":{"description":"Profit in dollars over each variant's Printify cost.","type":"number"},"markupPercent":{"description":"Percent over each variant's Printify cost.","type":"number"}}}},"required":["productId"]}},"confirmToken":{"type":"string","minLength":1,"maxLength":100}},"required":["shop","edits","confirmToken"]},"annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":true,"openWorldHint":true},"_meta":{"ui":{"resourceUri":"ui://productify/cards-v1.html"},"ui/resourceUri":"ui://productify/cards-v1.html","openai/toolInvocation/invoking":"Saving the changes","openai/toolInvocation/invoked":"Changes saved"}}],"resources":[{"uri":"ui://productify/cards-v1.html","name":"Productify card","mimeType":"text/html;profile=mcp-app"}],"prompts":[]}