@dynamic-mockups/mcp 1.0.8 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +17 -12
  2. package/package.json +3 -3
  3. package/src/index.js +261 -1
package/README.md CHANGED
@@ -70,6 +70,9 @@ If you want to connect via HTTP instead of NPX, use:
70
70
  | `create_collection` | Create a new collection |
71
71
  | `get_mockups` | Get list of available mockups with optional filters |
72
72
  | `get_mockup_by_uuid` | Retrieve a specific mockup by UUID |
73
+ | `search_products` | Search the POD product catalog used to ground MockAnything AI generations |
74
+ | `create_mockanything_mockup` | Create a new MockAnything AI mockup template from a prompt or image URL |
75
+ | `get_mockanything_status` | Poll the status of a MockAnything AI mockup creation task |
73
76
  | `create_render` | Create a single mockup render with design assets (1 credit) |
74
77
  | `create_batch_render` | Render multiple mockups in one request (1 credit per image) |
75
78
  | `export_print_files` | Export high-resolution print files for production |
@@ -81,18 +84,20 @@ If you want to connect via HTTP instead of NPX, use:
81
84
 
82
85
  Ask your AI assistant:
83
86
 
84
- | Use Case | Example Prompt |
85
- |----------|----------------|
86
- | Embed editor | "Add the full mockup editor to my web application" |
87
- | List catalogs | "Get my Dynamic Mockups catalogs" |
88
- | Browse mockups | "Show me all mockups in my T-shirt collection" |
89
- | Single render | "Create a mockup render using any T-shirt mockup with my artwork from url: https://example.com/my-design.png" |
90
- | Batch render | "Render my artwork from url: https://example.com/my-design.png on all mockups in the Winter T-shirt collection" |
91
- | Create collection | "Create a new collection called Summer 2025 Hoodies" |
92
- | Upload PSD | "Upload my PSD mockup from url: https://example.com/my-mockup.psd and create a template from it" |
93
- | API info | "What are the rate limits and supported file formats for Dynamic Mockups?" |
94
- | Print files | "Export print-ready files at 300 DPI for my poster mockup" |
95
- | Embroidery effect | "Transform my logo into an embroidery effect from url: https://example.com/my-logo.png" |
87
+ | Use Case | Example Prompt |
88
+ |--------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------|
89
+ | Embed editor | "Add the full mockup editor to my web application" |
90
+ | List catalogs | "Get my Dynamic Mockups catalogs" |
91
+ | Browse mockups | "Show me all mockups in my T-shirt collection" |
92
+ | Single render | "Create a mockup render using any T-shirt mockup with my artwork from url: https://example.com/my-design.png" |
93
+ | Batch render | "Render my artwork from url: https://example.com/my-design.png on all mockups in the Winter T-shirt collection" |
94
+ | Create collection | "Create a new collection called Summer 2025 Hoodies" |
95
+ | Upload PSD | "Upload my PSD mockup from url: https://example.com/my-mockup.psd and create a template from it" |
96
+ | API info | "What are the rate limits and supported file formats for Dynamic Mockups?" |
97
+ | Print files | "Export print-ready files at 300 DPI for my poster mockup" |
98
+ | Embroidery effect | "Transform my logo into an embroidery effect from url: https://example.com/my-logo.png" |
99
+ | Create a Mockup from Prompt | "Create a mockup of a guy wearing a Gildan 5000 t-shirt while running, then render my logo from url: https://example.com/my-logo.png on it" |
100
+ | Create a Mockup from Image URL | "Turn this product photo into a mockup: https://example.com/product.jpg, and render my artwork on it" |
96
101
 
97
102
  ## Error Handling
98
103
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dynamic-mockups/mcp",
3
- "version": "1.0.8",
3
+ "version": "1.1.0",
4
4
  "description": "Official Dynamic Mockups MCP Server - Generate product mockups with AI assistants",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
@@ -35,8 +35,8 @@
35
35
  "url": "https://github.com/dynamic-mockups/mcp/issues"
36
36
  },
37
37
  "dependencies": {
38
- "@modelcontextprotocol/sdk": "^1.0.0",
39
- "axios": "^1.6.0",
38
+ "@modelcontextprotocol/sdk": "^1.29.0",
39
+ "axios": "^1.15.2",
40
40
  "cors": "^2.8.5",
41
41
  "express": "^4.21.0"
42
42
  },
package/src/index.js CHANGED
@@ -540,6 +540,12 @@ function getApiKey(extra) {
540
540
  // 2. Use create_render (single) or create_batch_render (multiple) to generate images
541
541
  // Note: get_mockups returns all data needed to render - no need to call get_mockup_by_uuid first!
542
542
  //
543
+ // WORKFLOW FOR CREATING NEW MOCKUPS WITH AI (MockAnything):
544
+ // 1. (Optional) Call search_products to find a POD product UUID for grounding
545
+ // 2. Call create_mockanything_mockup with prompt or image_url -> returns task_id
546
+ // 3. Poll get_mockanything_status with task_id until state=SUCCESS -> returns mockup payload
547
+ // 4. Use mockup.uuid as mockup_uuid in create_render (works exactly like classic mockups)
548
+ //
543
549
  // WHEN TO USE EACH TOOL:
544
550
  // - get_api_info: First call when user asks about limits, pricing, or capabilities
545
551
  // - embed_mockup_editor: When user wants to embed the mockup editor in their website/app
@@ -547,6 +553,9 @@ function getApiKey(extra) {
547
553
  // - get_collections: When user wants to browse mockup groups or find mockups by category
548
554
  // - get_mockups: PRIMARY tool - lists templates WITH smart_object UUIDs ready for rendering
549
555
  // - get_mockup_by_uuid: Only when user needs ONE specific template (already has UUID)
556
+ // - search_products: Find a POD product UUID to ground MockAnything AI generations
557
+ // - create_mockanything_mockup: Create a brand-new mockup on the fly via AI prompt or image URL
558
+ // - get_mockanything_status: Poll a MockAnything task until the mockup is ready for rendering
550
559
  // - create_render: For generating 1 mockup image
551
560
  // - create_batch_render: For generating 2+ mockup images (more efficient)
552
561
  // - export_print_files: When user needs production-ready files with specific DPI
@@ -790,6 +799,167 @@ RETURNS: Single mockup with:
790
799
  },
791
800
  },
792
801
 
802
+ // ─────────────────────────────────────────────────────────────────────────────
803
+ // MOCKANYTHING AI TOOLS
804
+ // ─────────────────────────────────────────────────────────────────────────────
805
+ {
806
+ name: "search_products",
807
+ description: `Search the Print-on-Demand (POD) product catalog used to ground MockAnything AI generations.
808
+
809
+ API: GET /mock-anything/products
810
+
811
+ WHEN TO USE: When user wants to anchor an AI-generated mockup around a specific product (e.g., "Gildan 5000 t-shirt", "ceramic mug") instead of letting the model pick a generic one.
812
+
813
+ WORKFLOW:
814
+ 1. Call this tool with a search term (matched against POD product names)
815
+ 2. Pick the desired product from the response
816
+ 3. Pass its uuid as product.uuid when calling create_mockanything_mockup
817
+
818
+ NOTE: Grounding is OPTIONAL. Skip this tool if you want the AI to compose freely from the prompt alone.
819
+
820
+ RETURNS: Array of {name, uuid} POD product entries matching the query.`,
821
+ inputSchema: {
822
+ type: "object",
823
+ properties: {
824
+ query: {
825
+ type: "string",
826
+ description: "REQUIRED. Search term matched against POD product names (e.g., 'gildan', 'mug', 'hoodie'). Must be non-empty.",
827
+ },
828
+ },
829
+ required: ["query"],
830
+ },
831
+ },
832
+ {
833
+ name: "create_mockanything_mockup",
834
+ description: `Create a new MockAnything AI mockup template on the fly. The resulting mockup behaves exactly like one returned by get_mockups - pass its uuid to create_render to print artwork on it.
835
+
836
+ API: POST /mock-anything/create
837
+ COST:
838
+ - prompt flow: 5 credits (seedream_4_0, default), 6 credits (seedream_4_5), 14 credits (nano_banana_2). Charged on SUCCESS, free on FAILURE.
839
+ - image_url flow: 4 credits per generation.
840
+
841
+ WHEN TO USE: When user wants to:
842
+ - Generate a brand-new mockup from a text prompt (e.g., "a person wearing a t-shirt in Tokyo")
843
+ - Convert an existing public image URL into a usable mockup template
844
+ - Create custom mockups not available in their existing template catalog
845
+
846
+ EXACTLY ONE of these must be provided:
847
+ - prompt: text used to AI-generate the mockup image. Asynchronous - returns task_id to poll.
848
+ - image_url: public URL to an existing image. The task usually completes on the first status poll.
849
+
850
+ WORKFLOW:
851
+ 1. (Optional) Call search_products to find a product UUID for grounding the AI
852
+ 2. Call this tool with prompt OR image_url
853
+ 3. Use the returned task_id with get_mockanything_status, polling every ~2 seconds until state=SUCCESS
854
+ 4. Use the returned mockup.uuid as mockup_uuid in create_render
855
+
856
+ MODELS (only apply to the prompt flow):
857
+ - seedream_4_0 (default, 5 credits, ~20s, medium quality) - quick iterations
858
+ - seedream_4_5 (6 credits, ~40s, good quality) - higher fidelity without the pro price
859
+ - nano_banana_2 (14 credits, ~30s, high quality) - production-ready final mockups
860
+
861
+ NOTES:
862
+ - product.uuid, model, and enhance_prompt only apply to the prompt flow (ignored otherwise).
863
+ - collections accepts existing collections (by uuid) or new ones (by name, find-or-create).
864
+ - Rate limit: 50 requests/minute on this endpoint.
865
+ - File uploads (multipart image_file) are not supported via MCP - host the image and pass image_url.
866
+
867
+ RETURNS: {task_id, status} - the task_id will also be the mockup.uuid once the task succeeds.`,
868
+ inputSchema: {
869
+ type: "object",
870
+ properties: {
871
+ prompt: {
872
+ type: "string",
873
+ description: "Text prompt used to AI-generate the mockup image. Required unless image_url is provided. Triggers asynchronous generation - poll status with the returned task_id.",
874
+ },
875
+ image_url: {
876
+ type: "string",
877
+ description: "Public URL of an existing image to use as the mockup. Required unless prompt is provided. Completes on the first status poll.",
878
+ },
879
+ enhance_prompt: {
880
+ type: "boolean",
881
+ description: "Optional. Run prompt enhancement before generation. Only applies to the prompt flow.",
882
+ },
883
+ product: {
884
+ type: "object",
885
+ description: "Optional. Product context used to ground the AI generation around a specific POD product type. Only applies to the prompt flow.",
886
+ properties: {
887
+ uuid: {
888
+ type: "string",
889
+ description: "POD product UUID. Get from search_products.",
890
+ },
891
+ },
892
+ },
893
+ model: {
894
+ type: "string",
895
+ enum: ["seedream_4_0", "seedream_4_5", "nano_banana_2"],
896
+ description: "Optional. AI model used for generation. Default: seedream_4_0. Only applies to the prompt flow.",
897
+ },
898
+ name: {
899
+ type: "string",
900
+ description: "Optional. Mockup name shown in the dashboard (max 255 chars). Defaults to the prompt or a generic fallback.",
901
+ },
902
+ collections: {
903
+ type: "array",
904
+ description: "Optional. Collections to attach the mockup to. Each item must have either uuid (existing collection) or name (new collection - find-or-create).",
905
+ items: {
906
+ type: "object",
907
+ properties: {
908
+ uuid: {
909
+ type: "string",
910
+ description: "UUID of an existing collection.",
911
+ },
912
+ name: {
913
+ type: "string",
914
+ description: "Name of a new collection to create and attach (max 255 chars).",
915
+ },
916
+ },
917
+ },
918
+ },
919
+ catalog_uuid: {
920
+ type: "string",
921
+ description: "Optional. UUID of the catalog to place the mockup in. Defaults to the workspace's default catalog.",
922
+ },
923
+ },
924
+ },
925
+ },
926
+ {
927
+ name: "get_mockanything_status",
928
+ description: `Poll the status of a MockAnything AI mockup creation task.
929
+
930
+ API: GET /mock-anything/status/{taskId}
931
+
932
+ WHEN TO USE: After calling create_mockanything_mockup, use this to track progress until the mockup is ready for rendering.
933
+
934
+ POLLING STRATEGY:
935
+ - Poll every ~2 seconds (recommended)
936
+ - prompt flow: AI generations typically finish in 10-30 seconds
937
+ - image_url flow: usually ready on the very first status call
938
+
939
+ STATES:
940
+ - PROGRESS / PENDING: Task is still running. image_url and mockup are null. Poll again shortly.
941
+ - SUCCESS: Task complete. image_url is populated and mockup contains everything needed for create_render.
942
+ - FAILURE: Task terminated without producing a mockup. No credits are charged.
943
+
944
+ ON SUCCESS - the mockup field has the same shape as a get_mockups entry (with type "mockanything"):
945
+ - mockup.uuid: pass as mockup_uuid in create_render
946
+ - mockup.smart_objects[].uuid: pass as smart_objects[].uuid in create_render to place artwork on each detected print area
947
+
948
+ From here, render the mockup exactly like a classic one - the Render API handles both types through the same endpoint.
949
+
950
+ RETURNS: {task_id, state, image_url, status, mockup}.`,
951
+ inputSchema: {
952
+ type: "object",
953
+ properties: {
954
+ task_id: {
955
+ type: "string",
956
+ description: "REQUIRED. The task_id returned from create_mockanything_mockup.",
957
+ },
958
+ },
959
+ required: ["task_id"],
960
+ },
961
+ },
962
+
793
963
  // ─────────────────────────────────────────────────────────────────────────────
794
964
  // RENDER TOOLS
795
965
  // ─────────────────────────────────────────────────────────────────────────────
@@ -1235,7 +1405,7 @@ RETURNS: {uuid, name} of the uploaded PSD file.`,
1235
1405
 
1236
1406
  API: POST /psd/delete
1237
1407
 
1238
- WHEN TO USE: When user wants to:
1408
+ WHEN TO USE: When user wants to:
1239
1409
  - Remove an uploaded PSD file
1240
1410
  - Clean up unused PSD files
1241
1411
  - Optionally remove all mockups derived from the PSD
@@ -1579,6 +1749,93 @@ async function handleCreateEmbroideryEffect(args, extra) {
1579
1749
  }
1580
1750
  }
1581
1751
 
1752
+ async function handleSearchMockanythingProducts(args, extra) {
1753
+ const apiKey = getApiKey(extra);
1754
+ const error = validateApiKey(apiKey);
1755
+ if (error) return error;
1756
+
1757
+ if (!args.query || !String(args.query).trim()) {
1758
+ return ResponseFormatter.error(
1759
+ "Missing required parameter",
1760
+ { solution: "Provide a non-empty query string to search POD product names." }
1761
+ );
1762
+ }
1763
+
1764
+ try {
1765
+ const params = new URLSearchParams();
1766
+ params.append("query", args.query);
1767
+
1768
+ const response = await createApiClient(apiKey, "search_products").get(`/mock-anything/products?${params}`);
1769
+ return ResponseFormatter.fromApiResponse(response);
1770
+ } catch (err) {
1771
+ return ResponseFormatter.fromError(err, "Failed to search MockAnything products");
1772
+ }
1773
+ }
1774
+
1775
+ async function handleCreateMockanythingMockup(args, extra) {
1776
+ const apiKey = getApiKey(extra);
1777
+ const error = validateApiKey(apiKey);
1778
+ if (error) return error;
1779
+
1780
+ const hasPrompt = !!args.prompt;
1781
+ const hasImageUrl = !!args.image_url;
1782
+
1783
+ if (!hasPrompt && !hasImageUrl) {
1784
+ return ResponseFormatter.error(
1785
+ "Missing required input",
1786
+ { solution: "Provide exactly one of prompt (for AI generation) or image_url (for an existing image)." }
1787
+ );
1788
+ }
1789
+ if (hasPrompt && hasImageUrl) {
1790
+ return ResponseFormatter.error(
1791
+ "Conflicting inputs",
1792
+ { solution: "Provide exactly one of prompt or image_url, not both." }
1793
+ );
1794
+ }
1795
+
1796
+ try {
1797
+ const payload = {};
1798
+ if (hasPrompt) payload.prompt = args.prompt;
1799
+ if (hasImageUrl) payload.image_url = args.image_url;
1800
+ if (args.enhance_prompt !== undefined) payload.enhance_prompt = args.enhance_prompt;
1801
+ if (args.product) payload.product = args.product;
1802
+ if (args.model) payload.model = args.model;
1803
+ if (args.name) payload.name = args.name;
1804
+ if (args.collections) payload.collections = args.collections;
1805
+ if (args.catalog_uuid) payload.catalog_uuid = args.catalog_uuid;
1806
+
1807
+ const response = await createApiClient(apiKey, "create_mockanything_mockup").post("/mock-anything/create", payload);
1808
+
1809
+ const successMessage = hasPrompt
1810
+ ? "MockAnything AI generation started. Poll get_mockanything_status with the returned task_id (every ~2s) until state=SUCCESS, then use mockup.uuid in create_render."
1811
+ : "MockAnything mockup creation started from image_url. Poll get_mockanything_status with the returned task_id - it usually completes on the first call.";
1812
+
1813
+ return ResponseFormatter.fromApiResponse(response, successMessage);
1814
+ } catch (err) {
1815
+ return ResponseFormatter.fromError(err, "Failed to create MockAnything mockup");
1816
+ }
1817
+ }
1818
+
1819
+ async function handleGetMockanythingStatus(args, extra) {
1820
+ const apiKey = getApiKey(extra);
1821
+ const error = validateApiKey(apiKey);
1822
+ if (error) return error;
1823
+
1824
+ if (!args.task_id) {
1825
+ return ResponseFormatter.error(
1826
+ "Missing required parameter",
1827
+ { solution: "Provide the task_id returned from create_mockanything_mockup." }
1828
+ );
1829
+ }
1830
+
1831
+ try {
1832
+ const response = await createApiClient(apiKey, "get_mockanything_status").get(`/mock-anything/status/${args.task_id}`);
1833
+ return ResponseFormatter.fromApiResponse(response);
1834
+ } catch (err) {
1835
+ return ResponseFormatter.fromError(err, "Failed to get MockAnything mockup status");
1836
+ }
1837
+ }
1838
+
1582
1839
  // =============================================================================
1583
1840
  // Tool Router
1584
1841
  // =============================================================================
@@ -1591,6 +1848,9 @@ const toolHandlers = {
1591
1848
  create_collection: handleCreateCollection,
1592
1849
  get_mockups: handleGetMockups,
1593
1850
  get_mockup_by_uuid: handleGetMockupByUuid,
1851
+ search_products: handleSearchMockanythingProducts,
1852
+ create_mockanything_mockup: handleCreateMockanythingMockup,
1853
+ get_mockanything_status: handleGetMockanythingStatus,
1594
1854
  create_render: handleCreateRender,
1595
1855
  create_batch_render: handleCreateBatchRender,
1596
1856
  export_print_files: handleExportPrintFiles,