instantclips-mcp 1.2.0 → 1.4.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.
@@ -7,34 +7,66 @@
7
7
  "serverInfo": {
8
8
  "name": "instantclips",
9
9
  "title": "InstantClips",
10
- "version": "0.2.0",
10
+ "version": "0.5.0",
11
11
  "websiteUrl": "https://instantclips.ai"
12
12
  },
13
- "instructions": "InstantClips turns a product into a short vertical marketing video.\n\nEvery video is drafted against a BRAND — a voice, a target market and a\nset of keywords. Getting the brand right matters more than anything else\nhere: a product drafted under the wrong company's voice renders perfectly\nand is still unusable. Never assume a product belongs to whatever brand\nthe account already has.\n\nStart by asking the user for their store's URL if you do not already know\nthe brand, and call `list_brands` to see what the account has. Unlike the\nwebsite, which takes a product link and gets out of the way, you can\nsimply ask — a short question here is cheaper than a wrongly branded\nvideo.\n\nThe workflow, in order:\n\n1. `import_product_from_url` with the product's page URL (or\n `create_product_from_images` with hosted image URLs). Both return\n immediately and import in the background.\n2. Poll `get_product` until `import_status` is \"imported\".\n - If it reports `brand_decision_required` with `drafting: false`, the\n storefront does not match any brand on the account. Stop and put the\n choice to the user: create a brand for it (`create_brand`) or attach\n it to one they already have (`set_product_brand`). Do not choose for\n them. No direction is drafted until this is settled.\n - Otherwise the import also drafts a video direction — a six-section\n creative plan (Hook / Content Focus / Format / Suggesting Visual\n Aesthetic / Execution Guidelines /\n Strict Guidelines & Restrictions) — so keep polling until\n `video_direction.drafting` is false.\n3. Show the drafted direction to the user. Edit it with\n `update_video_direction`, or roll a completely different angle with\n `redraft_video_direction`. The direction is optional: an empty one is\n valid and generation still works.\n4. `generate_video` — this SPENDS THE USER'S CREDITS. Get the user's\n explicit go-ahead first, and tell them the credit cost that\n `get_product` reports.\n5. Poll `get_video` until status is \"done\", then give the user\n `output_url` (the finished MP4) and `share_url` (a public page).\n\nA render takes a few minutes. Poll every 20-30 seconds rather than in a\ntight loop, and tell the user what you are waiting on.\n",
13
+ "instructions": "InstantClips turns a product into a short vertical marketing video.\n\nEvery video is drafted against a BRAND — a voice, a target market and a\nset of keywords. Getting the brand right matters more than anything else\nhere: a product drafted under the wrong company's voice renders perfectly\nand is still unusable. Never assume a product belongs to whatever brand\nthe account already has.\n\nStart by asking the user for their store's URL if you do not already know\nthe brand, and call `list_brands` to see what the account has. Unlike the\nwebsite, which takes a product link and gets out of the way, you can\nsimply ask — a short question here is cheaper than a wrongly branded\nvideo.\n\nThe workflow, in order:\n\n1. `import_product_from_url` with the product's page URL (or\n `create_product_from_images` with hosted image URLs). Both return\n immediately and import in the background. If the user already made\n the product on the website — dropped photos on the workbench, pasted\n a link there — find it with `list_products` (newest first) and\n continue from step 2.\n2. Poll `get_product` until `import_status` is \"imported\".\n - If it reports `brand_decision_required` with `drafting: false`, the\n brand could not be settled: the storefront does not match any brand\n on the account, or (photos) there was no page to detect one from.\n Stop and put the choice to the user: create a brand for it\n (`create_brand`) or attach it to one they already have\n (`set_product_brand`). Do not choose for them. For a photos product\n nothing was detected, so `create_brand` needs the name from the\n user, and the voice, target market and keywords they can give you.\n No direction is drafted until this is settled.\n - Otherwise the import also drafts a video direction — a six-section\n creative plan (Hook / Content Focus / Format / Suggesting Visual\n Aesthetic / Execution Guidelines /\n Strict Guidelines & Restrictions) — so keep polling until\n `video_direction.drafting` is false.\n3. Show the drafted direction to the user. Edit it with\n `update_video_direction`, or roll a completely different angle with\n `redraft_video_direction`. The direction is optional: an empty one is\n valid and generation still works. The render settings — ratio,\n resolution, duration_seconds, enable_audio — are parameters of\n `update_video_direction` too, and are never read from the direction\n text. So are the photos: `images` in `get_product` lists every one\n with `usable` and `selected`, and `selected_image_ids` chooses which\n the render uses. `format` and `format_options` name the angle a\n redraft can pin. `update_product` corrects the facts a draft is\n written from (name, description, price, the posted link, the photos)\n and `update_brand` the identity (voice, market, keywords); both feed\n the next draft, so redraft after.\n4. `generate_video`, passing `expected_credit_cost` — this SPENDS THE\n USER'S CREDITS. Get the user's explicit go-ahead first, and tell\n them the credit cost that `get_product` reports; the launch is\n refused, uncharged, if that number no longer matches.\n5. Poll `get_video` until status is \"done\", then give the user\n `output_url` (the finished MP4) and `share_url` (a public page).\n On a free account the MP4 carries the InstantClips watermark\n (`watermarked` is true); buying credits removes it from every video\n on the account.\n\nEvery get_product response carries `next_step`: what to do now and the\ntool to do it with. Read it before choosing a tool — it covers the\nstates this list does not: a failed import, a failed or stalled\ndirection draft, photos the video model will not take, a failed\nrender, a balance short of the cost.\n\nA product whose video has been generated is not finished with, but a\ngenerated video cannot be changed: its direction locks the moment\ngeneration starts, and re-importing the same URL returns the same\nproduct rather than a fresh one. Editing or redrafting such a product\nopens its next video's draft, seeded from the last one (the response\nsays `opened_new_video: true`), and `generate_video` with no draft\nrenders another take of the last plan as a new video. Continue from\nstep 3 either way.\n\nA render takes a few minutes. Poll every 20-30 seconds rather than in a\ntight loop, and tell the user what you are waiting on.\n",
14
14
  "tools": [
15
15
  {
16
16
  "name": "list_brands",
17
17
  "title": "List the account's brands",
18
18
  "description": "List the brands on this account, with the plan's brand limit and whether\nanother brand can be created.\n\nA brand carries the identity every video is drafted against: its voice,\nits target market and its keywords. A product must belong to the brand it\nactually comes from — a product drafted under another company's voice is\nwrong even though it renders fine.\n\nCall this before answering a `brand_decision_required` from\n`get_product`, and whenever the user needs to choose or name a brand.\n\nThis does not spend credits.\n",
19
19
  "inputSchema": {
20
- "$schema": "https://json-schema.org/draft/2020-12/schema",
20
+ "type": "object",
21
21
  "properties": {},
22
22
  "required": [],
23
- "type": "object"
23
+ "$schema": "https://json-schema.org/draft/2020-12/schema"
24
24
  },
25
25
  "annotations": {
26
+ "readOnlyHint": true,
26
27
  "destructiveHint": false,
27
28
  "idempotentHint": true,
28
- "openWorldHint": false,
29
- "readOnlyHint": true
29
+ "openWorldHint": false
30
+ }
31
+ },
32
+ {
33
+ "name": "list_products",
34
+ "title": "List the account's products",
35
+ "description": "List the account's products, newest first — the ones imported here, on\nthe website, or from photos dropped on the workbench. Use it to find a\nproduct_id you do not have: a product the user made on the website, or\none from an earlier conversation. Then `get_product` for its full state.\n\n`query` matches the name or the source URL, `brand_id` narrows to one\nbrand (see `list_brands`), and `limit` caps the list (default 20, at\nmost 50). A product still waiting on its brand decision shows\n`brand_decision_required: true` and no brand.\n\nThis does not spend credits.\n",
36
+ "inputSchema": {
37
+ "type": "object",
38
+ "properties": {
39
+ "query": {
40
+ "type": "string",
41
+ "description": "Matches the product's name or source URL, case-insensitively."
42
+ },
43
+ "brand_id": {
44
+ "type": "string",
45
+ "description": "Only this brand's products."
46
+ },
47
+ "limit": {
48
+ "type": "integer",
49
+ "minimum": 1,
50
+ "maximum": 50,
51
+ "description": "How many, newest first. Default 20."
52
+ }
53
+ },
54
+ "required": [],
55
+ "$schema": "https://json-schema.org/draft/2020-12/schema"
56
+ },
57
+ "annotations": {
58
+ "readOnlyHint": true,
59
+ "destructiveHint": false,
60
+ "idempotentHint": true,
61
+ "openWorldHint": false
30
62
  }
31
63
  },
32
64
  {
33
65
  "name": "import_product_from_url",
34
66
  "title": "Import a product from its page URL",
35
- "description": "Start a new InstantClips product from a product page URL (a storefront\nlisting, e.g. a Shopify product page).\n\nReturns immediately with a product_id — the scrape, the image download\nand the first video-direction draft all run in the background. Poll\n`get_product` until `import_status` is \"imported\" and\n`video_direction.drafting` is false, which usually takes under a minute.\n\nPasting a URL that was already imported on this account returns that\nexisting product instead of creating a duplicate.\n\nIf the storefront name does not exactly match a brand this account has\nalready reviewed, the import stops on a brand decision instead of\nguessing: `get_product` will report `brand_decision_required`, and no\nvideo direction is drafted until it is resolved with `create_brand` or\n`set_product_brand`. Do not assume the account's existing brand — a\nproduct from a different company drafted under the wrong brand's voice\nis the failure this prevents. Pass `brand_id` only when the user has\ntold you which brand this product belongs to.\n\nThis does not spend credits. Only `generate_video` does.\n",
67
+ "description": "Start a new InstantClips product from a product page URL (a storefront\nlisting, e.g. a Shopify product page).\n\nReturns immediately with a product_id — the scrape, the image download\nand the first video-direction draft all run in the background. Poll\n`get_product` until `import_status` is \"imported\" and\n`video_direction.drafting` is false, which usually takes under a minute.\n\nPasting a URL that was already imported on this account returns that\nexisting product instead of creating a duplicate. If that import had\nfailed, pasting it again retries it (`retried` is true). If its video\nhas already been generated, editing or redrafting opens the next\nvideo's draft. Either way the response's `next_step` says what to do now.\n\nIf the storefront name does not exactly match a brand this account has\nalready reviewed, the import stops on a brand decision instead of\nguessing: `get_product` will report `brand_decision_required`, and no\nvideo direction is drafted until it is resolved with `create_brand` or\n`set_product_brand`. Do not assume the account's existing brand — a\nproduct from a different company drafted under the wrong brand's voice\nis the failure this prevents. Pass `brand_id` only when the user has\ntold you which brand this product belongs to.\n\nDirection drafting sends product facts, photos and brand context to\nan external AI service when the product is ready and its brand is settled.\n\nA store-domain ownership restriction refuses the import and sends a\nsupport notification containing account and store information.\n\nThis does not spend credits. Only `generate_video` does.\n",
36
68
  "inputSchema": {
37
- "$schema": "https://json-schema.org/draft/2020-12/schema",
69
+ "type": "object",
38
70
  "properties": {
39
71
  "url": {
40
72
  "type": "string",
@@ -48,21 +80,21 @@
48
80
  "required": [
49
81
  "url"
50
82
  ],
51
- "type": "object"
83
+ "$schema": "https://json-schema.org/draft/2020-12/schema"
52
84
  },
53
85
  "annotations": {
54
- "destructiveHint": false,
86
+ "readOnlyHint": false,
87
+ "destructiveHint": true,
55
88
  "idempotentHint": false,
56
- "openWorldHint": true,
57
- "readOnlyHint": false
89
+ "openWorldHint": true
58
90
  }
59
91
  },
60
92
  {
61
93
  "name": "create_product_from_images",
62
94
  "title": "Create a product from image URLs",
63
- "description": "Start a new InstantClips product from hosted product photos, for a\nproduct that has no public page to scrape.\n\nImages must be publicly reachable URLs — this endpoint cannot read files\nfrom the caller's machine. Images larger than\n8MB are skipped; at most\n9 are used in a render.\n\nReturns immediately with a product_id; the downloads and the first\nvideo-direction draft run in the background. Poll `get_product` until\n`import_status` is \"imported\".\n\nPrefer `import_product_from_url` when a product page exists — the scrape\nalso collects the name, description, price and brand identity, which\nmake for a far better direction draft than images alone.\n\nThis does not spend credits. Only `generate_video` does.\n",
95
+ "description": "Start a new InstantClips product from hosted product photos, for a\nproduct that has no public page to scrape.\n\nImages must be publicly reachable URLs — this endpoint cannot read files\nfrom the caller's machine. Images larger than\n8MB are skipped; at most\n9 are used in a render.\n\nReturns immediately with a product_id; the downloads run in the\nbackground. Poll `get_product` until `import_status` is \"imported\".\n\nPhotos carry no brand identity, so nothing can detect the brand here.\nWithout `brand_id` the product waits on a brand decision\n(`brand_decision_required` on the response and on `get_product`) and\nno video direction is drafted until it is settled with\n`set_product_brand` or `create_brand`. Ask the user which brand this\nis; do not pick for them.\n\nPrefer `import_product_from_url` when a product page exists — the scrape\nalso collects the name, description, price and brand identity, which\nmake for a far better direction draft than images alone.\n\nDirection drafting sends product facts, photos and brand context to\nan external AI service when the product is ready and its brand is settled.\n\nThis does not spend credits. Only `generate_video` does.\n",
64
96
  "inputSchema": {
65
- "$schema": "https://json-schema.org/draft/2020-12/schema",
97
+ "type": "object",
66
98
  "properties": {
67
99
  "image_urls": {
68
100
  "type": "array",
@@ -86,28 +118,28 @@
86
118
  },
87
119
  "brand_id": {
88
120
  "type": "string",
89
- "description": "Which brand this product belongs to, from `list_brands`. There is no page to scrape here, so nothing can detect the brand for you: confirm it with the user rather than letting it fall through to the account's default brand."
121
+ "description": "Optional, and only when the user has said which brand this product belongs to (from `list_brands`). Omit it and the product waits on a brand decision instead of falling through to the account's default brand."
90
122
  }
91
123
  },
92
124
  "required": [
93
125
  "image_urls",
94
126
  "name"
95
127
  ],
96
- "type": "object"
128
+ "$schema": "https://json-schema.org/draft/2020-12/schema"
97
129
  },
98
130
  "annotations": {
131
+ "readOnlyHint": false,
99
132
  "destructiveHint": false,
100
133
  "idempotentHint": false,
101
- "openWorldHint": true,
102
- "readOnlyHint": false
134
+ "openWorldHint": true
103
135
  }
104
136
  },
105
137
  {
106
138
  "name": "get_product",
107
139
  "title": "Get a product and its video direction",
108
- "description": "Read a product: what the import found, the current video direction and\nsettings, and every video generated from it.\n\nUse this to poll after `import_product_from_url` or\n`create_product_from_images`. The product is ready to work with when\n`import_status` is \"imported\" AND `video_direction.drafting` is false.\nPoll every 20-30 seconds; the whole thing normally settles inside a\nminute.\n\n`import_status` values: \"pending\" and \"importing\" mean keep polling;\n\"imported\" means done; \"failed\" means it did not work and\n`import_failed_reason` says why.\n\n`video_direction.credit_cost` is what `generate_video` will charge for\nthe current settings.\n",
140
+ "description": "Read a product: what the import found, the current video direction and\nsettings, and every video generated from it.\n\nUse this to poll after `import_product_from_url` or\n`create_product_from_images`. The product is ready to work with when\n`import_status` is \"imported\", there is no `brand_decision_required`,\nAND `video_direction.drafting` is false. If a brand decision is present\nwith `drafting: false`, ask the user to choose a brand and resolve it\nwith `create_brand` or `set_product_brand` before waiting for a direction.\nPoll every 20-30 seconds while import or drafting is in progress.\n\n`import_status` values: \"pending\" and \"importing\" mean keep polling;\n\"imported\" means done; \"failed\" means it did not work and\n`import_failed_reason` says why.\n\n`video_direction.credit_cost` is what `generate_video` will charge for\nthe current settings. `duration_seconds`, `ratio`, `resolution` and\n`enable_audio` are those settings; change them with\n`update_video_direction`, not in the direction text.\n\nOnce generation has started the direction is locked and\n`video_direction.editable` is false. Editing or redrafting then opens\nthe next video's draft, and `next_step` says so.\n",
109
141
  "inputSchema": {
110
- "$schema": "https://json-schema.org/draft/2020-12/schema",
142
+ "type": "object",
111
143
  "properties": {
112
144
  "product_id": {
113
145
  "type": "string",
@@ -117,21 +149,21 @@
117
149
  "required": [
118
150
  "product_id"
119
151
  ],
120
- "type": "object"
152
+ "$schema": "https://json-schema.org/draft/2020-12/schema"
121
153
  },
122
154
  "annotations": {
155
+ "readOnlyHint": true,
123
156
  "destructiveHint": false,
124
157
  "idempotentHint": true,
125
- "openWorldHint": false,
126
- "readOnlyHint": true
158
+ "openWorldHint": false
127
159
  }
128
160
  },
129
161
  {
130
162
  "name": "create_brand",
131
163
  "title": "Create a brand for a product",
132
- "description": "Create a new brand from the identity detected on a product that is\nwaiting on `brand_decision_required`, and attach the product to it.\n\nUse this when the product belongs to a company the account has no brand\nfor yet — the usual case when someone brings a new store. The brand's\nvoice, target market and keywords are taken from what the storefront\nscrape drafted; the user can rename it with `name`.\n\nAsk the user before calling this. It consumes one of the plan's brand\nslots, and on a plan that has run out this fails with a brand-limit\nerror — at which point the choices are to attach the product to an\nexisting brand with `set_product_brand`, to re-point an existing brand\nat this identity with `set_product_brand` and `replace_identity: true`,\nor to upgrade.\n\nOnce this returns, the video direction starts drafting: poll\n`get_product` until `video_direction.drafting` is false.\n\nThis does not spend credits.\n",
164
+ "description": "Create a new brand for a product that is waiting on\n`brand_decision_required`, and attach the product to it.\n\nUse this when the product belongs to a company the account has no brand\nfor yet — the usual case when someone brings a new store. For a product\nimported from a URL the brand's name, voice, target market and keywords\nare taken from what the storefront scrape drafted; the user can rename\nit with `name`. For a product created from photos nothing was detected\n(`detected_brand_name` is null), so `name` is required and `voice`,\n`target_market` and `keywords` should come from the user — ask them how\nthe brand sounds and who it sells to. Anything you pass overrides the\ndetected value.\n\nAsk the user before calling this. It consumes one of the plan's brand\nslots, and on a plan that has run out this fails with a brand-limit\nerror — at which point the choices are to attach the product to an\nexisting brand with `set_product_brand`, to re-point an existing brand\nat this identity with `set_product_brand` and `replace_identity: true`,\nor to upgrade.\n\nOnce this returns, the video direction starts drafting: poll\n`get_product` until `video_direction.drafting` is false.\n\nDirection drafting sends product facts, photos and brand context to\nan external AI service when the product is ready and its brand is settled.\n\nThis does not spend credits.\n",
133
165
  "inputSchema": {
134
- "$schema": "https://json-schema.org/draft/2020-12/schema",
166
+ "type": "object",
135
167
  "properties": {
136
168
  "product_id": {
137
169
  "type": "string",
@@ -139,27 +171,42 @@
139
171
  },
140
172
  "name": {
141
173
  "type": "string",
142
- "description": "Optional. Overrides the detected storefront name for the new brand."
174
+ "description": "The brand's name. Optional when a storefront name was detected (it overrides it); required for a product created from photos."
175
+ },
176
+ "voice": {
177
+ "type": "string",
178
+ "description": "Optional. How the brand talks, in a sentence or two — the tone every video direction is drafted in."
179
+ },
180
+ "target_market": {
181
+ "type": "string",
182
+ "description": "Optional. Who the brand sells to, as \"Region, Language\" (e.g. \"US, English\"). Sets the market and spoken language of every video on the brand."
183
+ },
184
+ "keywords": {
185
+ "type": "array",
186
+ "items": {
187
+ "type": "string"
188
+ },
189
+ "description": "Optional. A few short keywords for the brand's themes and audience — generic enough to survive a different product."
143
190
  }
144
191
  },
145
192
  "required": [
146
193
  "product_id"
147
194
  ],
148
- "type": "object"
195
+ "$schema": "https://json-schema.org/draft/2020-12/schema"
149
196
  },
150
197
  "annotations": {
198
+ "readOnlyHint": false,
151
199
  "destructiveHint": false,
152
200
  "idempotentHint": false,
153
- "openWorldHint": false,
154
- "readOnlyHint": false
201
+ "openWorldHint": true
155
202
  }
156
203
  },
157
204
  {
158
205
  "name": "set_product_brand",
159
206
  "title": "Attach a product to an existing brand",
160
- "description": "Attach a product waiting on `brand_decision_required` to one of the\naccount's existing brands. Use `list_brands` to see them.\n\nOnly do this when the user has confirmed the product really belongs to\nthat brand. Attaching a product to an unrelated brand is not a cosmetic\nmislabel: every video is drafted in that brand's voice, to its target\nmarket, with its keywords.\n\nBy default the brand's existing identity is left untouched. Pass\n`replace_identity: true` to instead overwrite that brand's voice, target\nmarket and keywords with the identity detected on this product — the\n\"re-point my brand at a different company\" move, for an account at its\nbrand limit. This rewrites a brand every other product on it shares, so\nconfirm it with the user explicitly first.\n\nOnce this returns, the video direction starts drafting: poll\n`get_product` until `video_direction.drafting` is false.\n\nThis does not spend credits.\n",
207
+ "description": "Attach a product waiting on `brand_decision_required` to one of the\naccount's existing brands. Use `list_brands` to see them.\n\nOnly do this when the user has confirmed the product really belongs to\nthat brand. Attaching a product to an unrelated brand is not a cosmetic\nmislabel: every video is drafted in that brand's voice, to its target\nmarket, with its keywords.\n\nBy default the brand's existing identity is left untouched. Pass\n`replace_identity: true` to instead overwrite that brand's voice, target\nmarket and keywords with the identity detected on this product — the\n\"re-point my brand at a different company\" move, for an account at its\nbrand limit. This rewrites a brand every other product on it shares, so\nconfirm it with the user explicitly first.\n\nOnce this returns, the video direction starts drafting: poll\n`get_product` until `video_direction.drafting` is false.\n\nReplacement also applies nonempty detected logo and colors, and can\nname an existing Default brand shell. Blank draft fields preserve saved\nvalues. An uploaded logo replaces the attached logo.\n\nDirection drafting sends product facts, photos and brand context to\nan external AI service when the product is ready and its brand is settled.\n\nThis does not spend credits.\n",
161
208
  "inputSchema": {
162
- "$schema": "https://json-schema.org/draft/2020-12/schema",
209
+ "type": "object",
163
210
  "properties": {
164
211
  "product_id": {
165
212
  "type": "string",
@@ -171,28 +218,125 @@
171
218
  },
172
219
  "replace_identity": {
173
220
  "type": "boolean",
174
- "description": "Optional, default false. Overwrite the brand's voice, target market and keywords with this product's detected identity. Affects every product on that brand — confirm with the user."
221
+ "description": "Optional, default false. Overwrite the brand's voice, target market and keywords with this product's detected identity. Also applies logo and colors; blank fields are preserved. Affects every product on that brand — confirm with the user."
175
222
  }
176
223
  },
177
224
  "required": [
178
225
  "product_id",
179
226
  "brand_id"
180
227
  ],
181
- "type": "object"
228
+ "$schema": "https://json-schema.org/draft/2020-12/schema"
229
+ },
230
+ "annotations": {
231
+ "readOnlyHint": false,
232
+ "destructiveHint": true,
233
+ "idempotentHint": false,
234
+ "openWorldHint": true
235
+ }
236
+ },
237
+ {
238
+ "name": "update_brand",
239
+ "title": "Edit a brand's identity",
240
+ "description": "Edit a brand: `name`, `voice` (how it sounds — a few sentences),\n`target_market` (where it sells, e.g. \"US/North America\"; it drives the\nspoken language) and `keywords` (the themes drafts lean on; the list you\npass replaces the old one). This is the identity every video for the\nbrand's products is drafted against. Drafts already written keep their\ntext — `redraft_video_direction` on a product to use the new identity.\n\nOnly the fields you pass change. `list_brands` has the ids and the\ncurrent values. This does not spend credits.\n",
241
+ "inputSchema": {
242
+ "type": "object",
243
+ "properties": {
244
+ "brand_id": {
245
+ "type": "string",
246
+ "description": "The brand's id, from list_brands."
247
+ },
248
+ "name": {
249
+ "type": "string",
250
+ "description": "The brand's name."
251
+ },
252
+ "voice": {
253
+ "type": "string",
254
+ "description": "How the brand sounds, in a few sentences."
255
+ },
256
+ "target_market": {
257
+ "type": "string",
258
+ "description": "Free text, e.g. \"US/North America\" or \"Japan\"."
259
+ },
260
+ "keywords": {
261
+ "type": "array",
262
+ "items": {
263
+ "type": "string"
264
+ },
265
+ "description": "The themes drafts lean on. Replaces the whole list."
266
+ }
267
+ },
268
+ "required": [
269
+ "brand_id"
270
+ ],
271
+ "$schema": "https://json-schema.org/draft/2020-12/schema"
182
272
  },
183
273
  "annotations": {
274
+ "readOnlyHint": false,
275
+ "destructiveHint": true,
276
+ "idempotentHint": true,
277
+ "openWorldHint": false
278
+ }
279
+ },
280
+ {
281
+ "name": "update_product",
282
+ "title": "Edit a product's facts, link and photos",
283
+ "description": "Edit what a product says about itself. `name`, `description` and\n`price` are the facts the direction draft is written from — fix a\nscrape that got them wrong, then `redraft_video_direction` so the next\ndraft uses them (the response's `next_step` says so when a direction\nalready exists). `link_url` is the product link posted with the video\nand shown on its share page: http(s) only, or empty to clear it.\n\n`add_image_urls` downloads hosted photos and adds them to the product,\nup to 9 per call and 8 MB each; the usable ones join the\nrender's selection while there is room, as the workbench's \"+\" tile\ndoes. `remove_image_ids` deletes photos by the image_id `get_product`\nlists; a removed photo leaves the selection by itself. Only the fields\nyou pass change.\n\nThis does not spend credits.\n",
284
+ "inputSchema": {
285
+ "type": "object",
286
+ "properties": {
287
+ "product_id": {
288
+ "type": "string",
289
+ "description": "The product's id."
290
+ },
291
+ "name": {
292
+ "type": "string",
293
+ "description": "The product's name."
294
+ },
295
+ "description": {
296
+ "type": "string",
297
+ "description": "What the product is; the draft reads it. Empty clears it."
298
+ },
299
+ "price": {
300
+ "type": "string",
301
+ "description": "Free text as the store shows it, e.g. \"$29\" or \"¥3,980\". Empty clears it."
302
+ },
303
+ "link_url": {
304
+ "type": "string",
305
+ "description": "The product link posted with the video. http(s) only; empty clears it."
306
+ },
307
+ "add_image_urls": {
308
+ "type": "array",
309
+ "items": {
310
+ "type": "string"
311
+ },
312
+ "description": "Hosted image URLs to download and add, in the order they should appear."
313
+ },
314
+ "remove_image_ids": {
315
+ "type": "array",
316
+ "items": {
317
+ "type": "string"
318
+ },
319
+ "description": "image_id values from get_product's images to delete."
320
+ }
321
+ },
322
+ "required": [
323
+ "product_id"
324
+ ],
325
+ "$schema": "https://json-schema.org/draft/2020-12/schema"
326
+ },
327
+ "annotations": {
328
+ "readOnlyHint": false,
184
329
  "destructiveHint": true,
185
330
  "idempotentHint": false,
186
- "openWorldHint": false,
187
- "readOnlyHint": false
331
+ "openWorldHint": true
188
332
  }
189
333
  },
190
334
  {
191
335
  "name": "update_video_direction",
192
336
  "title": "Edit the video direction and render settings",
193
- "description": "Edit the creative direction and render settings for a product's next\nvideo. Only the fields you pass are changed; everything else keeps its\ncurrent value.\n\n`creative_direction` is the plan the render is built from. It is free\ntext, but the drafts follow a six-section shape that works well and is\nworth preserving when editing:\n\n Hook: ...\n Content Focus: ...\n Format: ...\n Execution Guidelines: ...\n Strict Guidelines & Restrictions: ...\n\nDo not invent a direction from nothing when one has not been drafted\nyet — call `redraft_video_direction` and edit what comes back. Leaving\nit empty is also valid: generation works without a direction.\n\n`creator_note` is different and smaller: the user's own short note to\nthe director (\"mention it is machine washable\", \"for Father's Day\"). It\nis carried through to the render verbatim, so put the user's words in\nit, not your paraphrase.\n\nOnly works before generation starts. This does not spend credits.\n",
337
+ "description": "Edit the creative direction and render settings for a product's next\nvideo. Only the fields you pass are changed; everything else keeps its\ncurrent value. Supplied text replaces the saved text; an empty creative\ndirection clears it. A target_market change updates the shared brand\nand affects future videos for its other products.\n\n`creative_direction` is the plan the render is built from. It is free\ntext, but the drafts follow a six-section shape that works well and is\nworth preserving when editing:\n\n Hook: ...\n Content Focus: ...\n Format: ...\n Suggesting Visual Aesthetic: ...\n Execution Guidelines: ...\n Strict Guidelines & Restrictions: ...\n\nDo not invent a direction from nothing when one has not been drafted\nyet — call `redraft_video_direction` and edit what comes back. Leaving\nit empty is also valid: generation works without a direction.\n\n`creator_note` is different and smaller: the user's own short note to\nthe director (\"mention it is machine washable\", \"for Father's Day\"). It\nis carried through to the render verbatim, so put the user's words in\nit, not your paraphrase.\n\n`selected_image_ids` chooses which of the product's photos the render\nuses, in order, by the image_id `get_product` lists under `images`\n(usable ones only, at most 9); an empty list restores the\ndefault, the first usable ones. The poll's `selected_image_ids` shows\nwhat would go out now.\n\n`duration_seconds` is the render length — 15, 20, 25 or 30 — and a\nsetting, not part of the direction: writing \"20 seconds\" into the text\nchanges nothing. Longer costs more; the response's `credit_cost` is\nthe new price, and the user must hear it before `generate_video`.\nAbove the plan's ceiling it clamps like resolution (free: 20s).\n\nA target_market change after a direction exists gets a `next_step` in\nthe response: the direction's wording sets the spoken language, so it\nneeds a redraft (or an edit) to match the new market.\n\nA launched video cannot change: if the product's last video has\nalready launched, this opens the next video's draft (seeded from that\nvideo) and edits that; the response says `opened_new_video: true` and\ncarries the new video_request_id.\n\nThis does not spend credits.\n",
194
338
  "inputSchema": {
195
- "$schema": "https://json-schema.org/draft/2020-12/schema",
339
+ "type": "object",
196
340
  "properties": {
197
341
  "product_id": {
198
342
  "type": "string",
@@ -223,7 +367,24 @@
223
367
  "720P",
224
368
  "1080P"
225
369
  ],
226
- "description": "1080P needs a paid plan; a pick above the plan's ceiling quietly becomes that ceiling (the response reports what was actually saved)."
370
+ "description": "1080P is available to credit-pack purchasers and eligible tiers; a pick above the account's ceiling becomes that ceiling (the response reports what was actually saved)."
371
+ },
372
+ "duration_seconds": {
373
+ "type": "integer",
374
+ "enum": [
375
+ 15,
376
+ 20,
377
+ 25,
378
+ 30
379
+ ],
380
+ "description": "Render length in seconds. Priced per second, so the response's credit_cost changes with it; a pick above the plan's ceiling becomes that ceiling (free accounts: 20). The direction text never sets the length — this does."
381
+ },
382
+ "selected_image_ids": {
383
+ "type": "array",
384
+ "items": {
385
+ "type": "string"
386
+ },
387
+ "description": "The photos the render uses, in order, by image_id from get_product's images; usable ones only, at most 9. An empty list restores the default (the first usable ones)."
227
388
  },
228
389
  "enable_audio": {
229
390
  "type": "boolean",
@@ -237,21 +398,21 @@
237
398
  "required": [
238
399
  "product_id"
239
400
  ],
240
- "type": "object"
401
+ "$schema": "https://json-schema.org/draft/2020-12/schema"
241
402
  },
242
403
  "annotations": {
243
- "destructiveHint": false,
404
+ "readOnlyHint": false,
405
+ "destructiveHint": true,
244
406
  "idempotentHint": true,
245
- "openWorldHint": false,
246
- "readOnlyHint": false
407
+ "openWorldHint": false
247
408
  }
248
409
  },
249
410
  {
250
411
  "name": "redraft_video_direction",
251
412
  "title": "Draft a new creative direction",
252
- "description": "Ask InstantClips to draft a fresh creative direction for this product's\nnext video, using the product's facts, its images and the brand's\nidentity. Use it to get a first draft, or to try a different angle when\nthe user does not like the current one.\n\nThis OVERWRITES the current direction — including any edits. Confirm with\nthe user before re-rolling a direction they have already worked on.\n\nThe draft runs in the background: this returns with `drafting` true, and\nyou poll `get_product` until `video_direction.drafting` is false (a few\nseconds). Rolling a fresh angle is the point, so calling it twice gives\ntwo different drafts, not the same one.\n\nThis does not spend credits.\n",
413
+ "description": "Ask InstantClips to draft a fresh creative direction for this product's\nnext video, using the product's facts, its images and the brand's\nidentity. Use it to get a first draft, or to try a different angle when\nthe user does not like the current one.\n\nThis OVERWRITES the current direction — including any edits. Confirm with\nthe user before re-rolling a direction they have already worked on.\n\nIf the product's last video has already launched, this opens the next\nvideo's draft (seeded from that video) and drafts into it; the response\nsays `opened_new_video: true` and carries the new video_request_id.\n\nThe draft runs in the background: this returns with `drafting` true, and\nyou poll `get_product` until `video_direction.drafting` is false (a few\nseconds). Rolling a fresh angle is the point, so calling it twice gives\ntwo different drafts, not the same one.\n\nDirection drafting sends product facts, photos and brand context to\nan external AI service when the product is ready and its brand is settled.\n\nThis does not spend credits.\n",
253
414
  "inputSchema": {
254
- "$schema": "https://json-schema.org/draft/2020-12/schema",
415
+ "type": "object",
255
416
  "properties": {
256
417
  "product_id": {
257
418
  "type": "string",
@@ -259,51 +420,56 @@
259
420
  },
260
421
  "format": {
261
422
  "type": "string",
262
- "description": "Optional. Pin a specific video format instead of letting the drafter pick one — e.g. \"unboxing\", \"before_after\". Unknown values are ignored, so leave it out unless the user asked for a particular kind of video."
423
+ "description": "Optional. Pin the angle instead of letting the drafter pick one: a key from video_direction.format_options in get_product (this product's shortlist, or the whole catalogue, each with a one-line summary). Unknown keys are ignored, so leave it out unless the user asked for a particular kind of video."
263
424
  }
264
425
  },
265
426
  "required": [
266
427
  "product_id"
267
428
  ],
268
- "type": "object"
429
+ "$schema": "https://json-schema.org/draft/2020-12/schema"
269
430
  },
270
431
  "annotations": {
432
+ "readOnlyHint": false,
271
433
  "destructiveHint": true,
272
434
  "idempotentHint": false,
273
- "openWorldHint": true,
274
- "readOnlyHint": false
435
+ "openWorldHint": true
275
436
  }
276
437
  },
277
438
  {
278
439
  "name": "generate_video",
279
440
  "title": "Generate the video (spends credits)",
280
- "description": "Render the video. THIS SPENDS THE USER'S CREDITS.\n\nAsk the user before calling this, every time. Tell them the cost first —\n`get_product` reports it as `video_direction.credit_cost`, and the\nuser's balance as `credits_remaining`. Credits are charged at launch,\nnot on completion; a failed render is refunded automatically.\n\nShow the user the creative direction and let them approve or edit it\nbefore you call this. Do not call it to \"see what happens\", to retry a\nrender that is still in progress, or as part of a batch you decided on\nyour own.\n\nReturns as soon as the render is queued. Poll `get_video` with the\nreturned video_request_id every 20-30 seconds until its status is\n\"done\" (a few minutes), then give the user `output_url` and\n`share_url`.\n\nIf the account cannot afford it, nothing is charged and the response\nsays so — tell the user to top up at the credits page rather than\nretrying.\n",
441
+ "description": "Render the video. THIS SPENDS THE USER'S CREDITS.\nProduct photos, brand identity and direction are sent to external\ngeneration services. Results have public share pages; generation can\ntrigger account emails, including a first-generation welcome email.\n\nAsk the user before calling this, every time. Tell them the cost first —\n`get_product` reports it as `video_direction.credit_cost`, and the\nuser's balance as `credits_remaining` — and pass that cost as\n`expected_credit_cost`: if it no longer matches (settings changed, a\nresolution was clamped), nothing is charged and the response says the\ncurrent cost. Credits are charged at launch, not on completion; a\nfailed render is refunded automatically.\n\nShow the user the creative direction and let them approve or edit it\nbefore you call this. Do not call it to \"see what happens\", to retry a\nrender that is still in progress, or as part of a batch you decided on\nyour own.\n\nReturns as soon as the render is queued. Poll `get_video` with the\nreturned video_request_id every 20-30 seconds until its status is\n\"done\" (a few minutes), then give the user `output_url` and\n`share_url`.\n\nIf the account cannot afford it, nothing is charged and the response\nsays so — tell the user to top up at the credits page rather than\nretrying.\n\nIf the product's last video is finished (done or failed) and there is\nno draft, this renders another take of the same plan as a new video,\nat the same cost; the response says `opened_new_video: true`. While a\nrender is in flight it refuses.\n",
281
442
  "inputSchema": {
282
- "$schema": "https://json-schema.org/draft/2020-12/schema",
443
+ "type": "object",
283
444
  "properties": {
284
445
  "product_id": {
285
446
  "type": "string",
286
447
  "description": "The product to render. Its current direction and settings are used as-is."
448
+ },
449
+ "expected_credit_cost": {
450
+ "type": "integer",
451
+ "description": "The credit cost you told the user — get_product's video_direction.credit_cost. It must still be the cost: if it has changed, nothing is charged and the response says the new number."
287
452
  }
288
453
  },
289
454
  "required": [
290
- "product_id"
455
+ "product_id",
456
+ "expected_credit_cost"
291
457
  ],
292
- "type": "object"
458
+ "$schema": "https://json-schema.org/draft/2020-12/schema"
293
459
  },
294
460
  "annotations": {
295
- "destructiveHint": false,
461
+ "readOnlyHint": false,
462
+ "destructiveHint": true,
296
463
  "idempotentHint": false,
297
- "openWorldHint": true,
298
- "readOnlyHint": false
464
+ "openWorldHint": true
299
465
  }
300
466
  },
301
467
  {
302
468
  "name": "get_video",
303
469
  "title": "Check a video's render status",
304
- "description": "Check one video's render.\n\n`status` values:\n \"generating\" — still rendering, keep polling every 20-30 seconds.\n \"done\" — finished; `output_url` is the MP4 and `share_url` is a\n public page to send someone.\n \"failed\" — `failed_reason` says why. The credits were refunded\n automatically; the user can retry from the product page.\n \"insufficient_credit\" — never launched; nothing was charged.\n \"pending\" — not launched yet; call `generate_video`.\n\nA render normally takes a few minutes. Tell the user what you are\nwaiting on rather than polling silently in a tight loop.\n",
470
+ "description": "Check one video's render.\n\n`status` values:\n \"generating\" — still rendering, keep polling every 20-30 seconds.\n \"done\" — finished; `output_url` is the MP4 and `share_url` is a\n public page to send someone. `watermarked` is true when\n that MP4 carries the InstantClips watermark (free\n accounts); buying credits switches every video on the\n account to the clean file, nothing is re-rendered.\n \"failed\" — `failed_reason` says why and what to change. The credits\n were refunded automatically. To try again, make the change\n with `update_video_direction` or `redraft_video_direction`\n (either opens the next video's draft), then `generate_video`.\n \"insufficient_credit\" — never launched; nothing was charged.\n \"pending\" — not launched yet; call `generate_video`.\n\n`next_step` says which of those applies right now.\n\nA render normally takes a few minutes. Tell the user what you are\nwaiting on rather than polling silently in a tight loop.\n",
305
471
  "inputSchema": {
306
- "$schema": "https://json-schema.org/draft/2020-12/schema",
472
+ "type": "object",
307
473
  "properties": {
308
474
  "video_request_id": {
309
475
  "type": "string",
@@ -313,13 +479,13 @@
313
479
  "required": [
314
480
  "video_request_id"
315
481
  ],
316
- "type": "object"
482
+ "$schema": "https://json-schema.org/draft/2020-12/schema"
317
483
  },
318
484
  "annotations": {
485
+ "readOnlyHint": true,
319
486
  "destructiveHint": false,
320
487
  "idempotentHint": true,
321
- "openWorldHint": false,
322
- "readOnlyHint": true
488
+ "openWorldHint": false
323
489
  }
324
490
  }
325
491
  ]
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "instantclips-mcp",
3
3
  "mcpName": "ai.instantclips/instantclips",
4
- "version": "1.2.0",
4
+ "version": "1.4.0",
5
5
  "description": "Use the hosted InstantClips MCP server from stdio-only clients.",
6
6
  "type": "module",
7
7
  "bin": {