@dynamic-mockups/mcp 1.0.7 → 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 +34 -27
  2. package/package.json +3 -3
  3. package/src/index.js +329 -0
package/README.md CHANGED
@@ -13,15 +13,15 @@ Add the following to your MCP client configuration file:
13
13
 
14
14
  ```json
15
15
  {
16
- "mcpServers": {
17
- "dynamic-mockups": {
18
- "command": "npx",
19
- "args": ["-y", "@dynamic-mockups/mcp"],
20
- "env": {
21
- "DYNAMIC_MOCKUPS_API_KEY": "your_api_key_here"
22
- }
16
+ "mcpServers": {
17
+ "dynamic-mockups": {
18
+ "command": "npx",
19
+ "args": ["-y", "@dynamic-mockups/mcp"],
20
+ "env": {
21
+ "DYNAMIC_MOCKUPS_API_KEY": "your_api_key_here"
23
22
  }
24
- }
23
+ }
24
+ }
25
25
  }
26
26
  ```
27
27
 
@@ -37,15 +37,15 @@ If you want to connect via HTTP instead of NPX, use:
37
37
 
38
38
  ```json
39
39
  {
40
- "mcpServers": {
41
- "dynamic-mockups": {
42
- "type": "http",
43
- "url": "https://mcp.dynamicmockups.com",
44
- "headers": {
45
- "x-api-key": "your_api_key_here"
46
- }
40
+ "mcpServers": {
41
+ "dynamic-mockups": {
42
+ "type": "http",
43
+ "url": "https://mcp.dynamicmockups.com",
44
+ "headers": {
45
+ "x-api-key": "your_api_key_here"
47
46
  }
48
- }
47
+ }
48
+ }
49
49
  }
50
50
  ```
51
51
 
@@ -70,27 +70,34 @@ 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 |
76
79
  | `upload_psd` | Upload a PSD file and optionally create a mockup template |
77
80
  | `delete_psd` | Delete a PSD file with optional related mockups deletion |
81
+ | `tool_create_embroidery_effect` | Transform any image into a realistic embroidery/stitched effect |
78
82
 
79
83
  ## Usage Examples
80
84
 
81
85
  Ask your AI assistant:
82
86
 
83
- | Use Case | Example Prompt |
84
- |----------|----------------|
85
- | Embed editor | "Add the full mockup editor to my web application" |
86
- | List catalogs | "Get my Dynamic Mockups catalogs" |
87
- | Browse mockups | "Show me all mockups in my T-shirt collection" |
88
- | Single render | "Create a mockup render using any T-shirt mockup with my artwork from url: https://example.com/my-design.png" |
89
- | Batch render | "Render my artwork from url: https://example.com/my-design.png on all mockups in the Winter T-shirt collection" |
90
- | Create collection | "Create a new collection called Summer 2025 Hoodies" |
91
- | Upload PSD | "Upload my PSD mockup from url: https://example.com/my-mockup.psd and create a template from it" |
92
- | API info | "What are the rate limits and supported file formats for Dynamic Mockups?" |
93
- | Print files | "Export print-ready files at 300 DPI for my poster mockup" |
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" |
94
101
 
95
102
  ## Error Handling
96
103
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dynamic-mockups/mcp",
3
- "version": "1.0.7",
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,12 +553,16 @@ 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
553
562
  // - upload_psd: When user wants to add their own PSD mockup template
554
563
  // - delete_psd: When user wants to remove an uploaded PSD
555
564
  // - create_collection: When user wants to organize mockups into groups
565
+ // - tool_create_embroidery_effect: When user wants to transform an image into embroidery/stitched effect
556
566
  //
557
567
  // =============================================================================
558
568
 
@@ -789,6 +799,167 @@ RETURNS: Single mockup with:
789
799
  },
790
800
  },
791
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
+
792
963
  // ─────────────────────────────────────────────────────────────────────────────
793
964
  // RENDER TOOLS
794
965
  // ─────────────────────────────────────────────────────────────────────────────
@@ -1257,6 +1428,48 @@ RETURNS: Success confirmation message.`,
1257
1428
  required: ["psd_uuid"],
1258
1429
  },
1259
1430
  },
1431
+
1432
+ // ─────────────────────────────────────────────────────────────────────────────
1433
+ // EFFECT TOOLS
1434
+ // ─────────────────────────────────────────────────────────────────────────────
1435
+ {
1436
+ name: "tool_create_embroidery_effect",
1437
+ description: `Transform any image into a realistic embroidery/stitched effect.
1438
+
1439
+ API: POST /tools/embroidery
1440
+ COST: 6 credits per request
1441
+
1442
+ WHEN TO USE: When user wants to:
1443
+ - Convert artwork/designs into embroidery style
1444
+ - Create stitched/embroidered versions of logos or images
1445
+ - Prepare designs for print-on-demand embroidery products
1446
+ - Transform existing artwork to look like embroidery before rendering on mockups
1447
+
1448
+ INPUT: Provide image via EITHER:
1449
+ - image_url: Public URL to the image (PNG, JPG, WEBP supported)
1450
+ - image_data_b64: Base64-encoded image data
1451
+ Only ONE input method is required per request.
1452
+
1453
+ TIPS FOR BEST RESULTS:
1454
+ - Use high-contrast images with clean edges
1455
+ - Simpler designs with fewer colors produce more realistic embroidery effects
1456
+ - The output can be used directly in mockup renders or saved to asset library
1457
+
1458
+ RETURNS: {export_path} - URL to the generated embroidery image (temporary, should be downloaded or saved to permanent storage).`,
1459
+ inputSchema: {
1460
+ type: "object",
1461
+ properties: {
1462
+ image_url: {
1463
+ type: "string",
1464
+ description: "Public URL to the image to transform. Supported formats: PNG, JPG, WEBP. Either image_url OR image_data_b64 must be provided.",
1465
+ },
1466
+ image_data_b64: {
1467
+ type: "string",
1468
+ description: "Base64-encoded image data. Either image_url OR image_data_b64 must be provided.",
1469
+ },
1470
+ },
1471
+ },
1472
+ },
1260
1473
  ];
1261
1474
 
1262
1475
  // =============================================================================
@@ -1511,6 +1724,118 @@ async function handleDeletePsd(args, extra) {
1511
1724
  }
1512
1725
  }
1513
1726
 
1727
+ async function handleCreateEmbroideryEffect(args, extra) {
1728
+ const apiKey = getApiKey(extra);
1729
+ const error = validateApiKey(apiKey);
1730
+ if (error) return error;
1731
+
1732
+ // Validate that at least one input method is provided
1733
+ if (!args.image_url && !args.image_data_b64) {
1734
+ return ResponseFormatter.error(
1735
+ "Missing required input",
1736
+ { solution: "Provide either image_url (public URL) or image_data_b64 (base64-encoded image data)." }
1737
+ );
1738
+ }
1739
+
1740
+ try {
1741
+ const payload = {};
1742
+ if (args.image_url) payload.image_url = args.image_url;
1743
+ if (args.image_data_b64) payload.image_data_b64 = args.image_data_b64;
1744
+
1745
+ const response = await createApiClient(apiKey, "tool_create_embroidery_effect").post("/tools/embroidery", payload);
1746
+ return ResponseFormatter.fromApiResponse(response, "Embroidery effect created (6 credits used)");
1747
+ } catch (err) {
1748
+ return ResponseFormatter.fromError(err, "Failed to create embroidery effect");
1749
+ }
1750
+ }
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
+
1514
1839
  // =============================================================================
1515
1840
  // Tool Router
1516
1841
  // =============================================================================
@@ -1523,11 +1848,15 @@ const toolHandlers = {
1523
1848
  create_collection: handleCreateCollection,
1524
1849
  get_mockups: handleGetMockups,
1525
1850
  get_mockup_by_uuid: handleGetMockupByUuid,
1851
+ search_products: handleSearchMockanythingProducts,
1852
+ create_mockanything_mockup: handleCreateMockanythingMockup,
1853
+ get_mockanything_status: handleGetMockanythingStatus,
1526
1854
  create_render: handleCreateRender,
1527
1855
  create_batch_render: handleCreateBatchRender,
1528
1856
  export_print_files: handleExportPrintFiles,
1529
1857
  upload_psd: handleUploadPsd,
1530
1858
  delete_psd: handleDeletePsd,
1859
+ tool_create_embroidery_effect: handleCreateEmbroideryEffect,
1531
1860
  };
1532
1861
 
1533
1862
  // =============================================================================