
Lamina — On-brand product photos, video & try-onsVerifiedFeatured
@Lamina
About Lamina — On-brand product photos, video & try-ons
Generate on brand product videos from Claude Code (or any assistant) in one line. Lamina turns a brief + your brand kit into finished product photos, video reels, and campaign banners - no prompt engineering; brand guardrails (colors, fonts, tone, style) enforced automatically. For developers: 14+ tools - lamina_brand (pull brand guidelines), lamina_run (product_shoot, vertical_reel, ad_variant, virtual_try_on, campaign_banner, brand_film), lamina_status (poll jobs). Bearer-token auth, ~12s/asset, 35+ variants per product, multi-channel auto-formatting. For marketers in Claude Code: describe the shot, get campaign-ready, on-brand creative back — no design tool, no photoshoot. Install: npx add-mcp https://app.uselamina.ai/mcp/agent Works with Claude, Claude Code, Cursor, Windsurf, VS Code, Zed, Raycast, n8n, Zapier. Free to start · Docs: docs.uselamina.ai
Connection details
https://app.uselamina.ai/mcp/agentSetup
claude mcp add lamina --transport http https://app.uselamina.ai/mcp/agentTools
22Discover Lamina apps (creative workflows) that can produce what the user wants. ALWAYS start here when the user asks to create new content — discover the right app first, then describe it, then run it. How to use it: 1. Provide an array of `keywords` describing the desired creative outcome. Be concrete: combine medium (image / video / audio), form (reel, banner, hero shot, headshot, voiceover), and context (ecommerce, social, lifestyle). Examples: ["product video", "reel", "9:16"], ["hero banner", "lifestyle photo"], ["voiceover", "narration"]. 2. Read the returned apps. Each entry shows the app's name, description, outputs, and estimated credit cost when known. Choose by PURPOSE match — does the app's actual delivery match the user's intent? Keyword overlap alone is not enough. 3. If no listed app fits, call this tool again with different / broader / more specific keywords. The catalog is large; rephrasing often surfaces matches you missed. 4. If after a few sensible searches you still cannot find a suitable app, tell the user honestly that the catalog has no app for this exact need — suggest the closest related app or propose they refine their goal. 5. Once a candidate looks right, call `lamina_describe` with its `appId` for the full parameter contract. The result is ordered by relevance. Apps may be owned by your workspace or shared publicly. `estimatedCredits` is omitted when it cannot be computed quickly — treat absence as "unknown", not zero.
Get the full input/output specification for a single Lamina app. Use it in the MANUAL flow (after `lamina_discover` and before `lamina_run`) when the calling LLM wants to inspect or verify an app's schema directly. The AGENTIC flow via `lamina_create` does discover + describe internally — no need to call describe before create. Returns: - `parameters[]` — every input the app accepts. Each entry has a stable `key` (used in `lamina_run.inputs`), a `type` (`text` / `options` / `url`), an optional `default`, and `accept`/`options`/`multiple` where relevant. - `outputs[]` — what the app produces. Each entry is `{ index, label, type: 'image'|'video'|'audio'|'text' }`. Labels are canonical identifiers — pass them verbatim to `lamina_run.outputs` when subsetting. - `estimatedCredits` — typical cost of one run (omitted when unknown). The user has NO form UI — they only see what you tell them in chat. Every parameter in `parameters[]` is something the workflow author wanted set; defaults shown are the AUTHOR's choices, not the user's authorization. Treat each parameter accordingly: - For USER-OWNED assets (their product, headshot, logo, brand asset, garment): never use the default. ASK the human in chat first — defaults here are demo placeholders that misrepresent the user's subject. - For PRESET / STYLE / REFERENCE groups (mood-board refs, style refs, palette refs, etc.) — often appearing as a numbered series of similar slots: ASK the human in chat ONCE per group — 'use the app's curated defaults or supply your own?' Don't silently default; the user can't see these slots exist. - For text/copy you can confidently draft from the brief (headlines, descriptions): draft. Otherwise ASK. - For dialog-derived settings (aspect ratio, variant count, output format): use the user's explicit input or hint; if absent, ASK. When in doubt about ANY parameter, ASK the human in chat before calling `lamina_run`. One extra question is cheaper than a wrong-output run. Constructing `inputs` for `lamina_run`: - Use the parameter `key` as the input key. Example: `inputs: { "your_photo_image_url": "https://..." }`. - For `type: "options"`, send the option label as a string (case-insensitive match). - For `type: "url"` with `multiple: true`, send an array of URLs. Otherwise send a single URL string. Never invent URLs. - Omit a parameter from `inputs` only when the user has explicitly authorized falling back to the workflow default.
Dispatch a run for an app the user has authorized. Pure trigger — no LLM, no brief analysis, no app picking. Takes an `appId` you already know (from `lamina_create.selectedApp.appId` after the agentic flow, or from `lamina_describe` in the manual flow) plus `inputs` keyed by parameter `key`, optionally `outputs` (label subset). How to use it: - Pass `appId` and `inputs`. `inputs` is a map keyed by parameter `key` from describe (option label for `options`, URL string for `url`, array of URLs for `url + multiple`). - Only include parameters the user has explicitly authorized — by giving the value in the brief, answering an ask in chat, or saying 'use defaults' on a surfaced preset group. Silent defaults on user-owned slots produce wrong-subject output. - `outputs` (optional): when the user asked for only a subset of the app's outputs (e.g. 'just the front view and the lifestyle shot'), pass `outputs: ['Front View', 'Lifestyle View']` with labels verbatim from `lamina_describe.outputs[].label` (case-insensitive). Omit or pass an empty array to produce every output the app declares (default). - `applyBrand` (optional): set true to make the output on-brand — Lamina folds the workspace's brand negatives + visual style onto the app's visual nodes before running. Your `inputs` still win over brand. Use it instead of hand-writing brand into every input. - Returns immediately with `{runId, workflowId, status}`. Most apps take 1–5 minutes (median ~2 min, p90 ~5 min). Poll with `lamina_status`. - On `Invalid inputs` error, the response includes `details: [{param, code, message}]`. Common causes: option label not in declared list, malformed URL, wrong type. On `outputs_resolution_failed`, the label you passed doesn't match any output on the app — re-check `lamina_describe.outputs[].label`. - For variants/series (e.g. "5 selfies with different celebrities"), call this tool once per variant in parallel. Each call returns its own `runId`.
Check the status of any Lamina run — polymorphic across atomic image-gen (`lamina_generate_image`), atomic video-gen (`lamina_generate_video`), app workflow runs (`lamina_run`), and agentic recipe runs. - Default: returns the current snapshot (`queued` / `running` / `completed` / `failed` / `cancelled`) and the result. The agent decides when to call again. - With `wait: true`: blocks server-side, polling every 2 seconds, until the run reaches a terminal state OR `timeoutSeconds` elapses (default 240, max 600). Atomic image runs typically finish in 5–30s; atomic video runs take 30s–5 min; app workflows 1–5 min (median ~2 min, p90 ~5 min). Pick `timeoutSeconds` accordingly. If the timeout fires, the response includes `"timeout": true` plus the current status; call again to keep waiting. Response shape depends on the run kind: - **Atomic image-gen runs**: when `completed`, the response has `output: { type: "image", url: "..." }` (singular). Pass the `url` to the user. - **Atomic video-gen runs**: when `completed`, the response has `output: { type: "video", url: "..." }` (singular). Pass the `url` to the user. - **App + freestyle runs**: when `completed`, every entry in `outputs[]` has a `url`. The `label` matches what you saw in `lamina_describe`. Pass URLs back to the user, or feed them into a follow-up `lamina_run` as reference assets. - When `failed`, `errorMessage` carries the top-level reason. Per-output failures (app runs) are in `outputs[i].error`. - While the run is `running`, surface progress to the user instead of making them wait silently.
List Lamina's curated atomic generation models. Each entry has `id`, `displayName`, `modality`, and — to help you pick deliberately rather than guess — `bestFor` (what the model is good at / when to reach for it), `cost` (`low`|`medium`|`high` relative credit tier), `speed` (`fast`|`standard`|`slow`), and `provider` (the infra that serves it: `fal`|`wavespeed`|`vertex`). Pass `modality: 'image'` (default) or `modality: 'video'` to scope the response. Use `bestFor` to match the task, and `cost`/`speed` to break ties — prefer a `low`/`fast` model unless the task needs the quality of a `high` one. After picking an `id`, call `lamina_models_describe({modelId})` to get the input contract before calling `lamina_generate_image` / `lamina_generate_video`.
Get the input contract for one atomic-generate model (image OR video). Returns `id`, `displayName`, `modality`, and a flat `paramSchema` (every accepted field, including `prompt`, with `type`, allowed `values`, `default`, `min`/`max`/`step`, and short field-level `description` text). Hybrid models present a single merged schema where mode-specific fields are marked optional; the description on each field tells you when it applies. Models that don't accept a prompt (e.g. `bria-bg-remove`) simply omit the `prompt` field from `paramSchema`. Polymorphic — tries image registry then video registry, so any id from `lamina_models_list({modality:'image'|'video'})` is accepted. Call this BEFORE `lamina_generate_image` / `lamina_generate_video` for a model you haven't used. The response is the contract — what you pass in `params` must match these field rules, and the cross-field constraints noted in each field's `description` (e.g. gpt-image-2's custom dimensions are capped at 8.3M pixels and 3:1 aspect).
Dispatch a single atomic image generation. Sibling of `lamina_create` (the agentic router) — use this when you already know which model fits, or when no app fits the brief. WORKFLOW: (1) `lamina_models_list({ modality: "image" })` → pick a model. (2) `lamina_models_describe({ modelId })` → read its flat `paramSchema`. (3) `lamina_generate_image({ model, prompt, params })` → dispatch, get runId. (4) `lamina_status({ runId, wait: true })` → poll until completed; the response has `output.url`. ONE TOOL, BOTH OPERATIONS: • Text-to-image — call with just `prompt` (and any text-mode params). The model id you picked is the only thing that selects the operation. • Image-to-image (edit / remix / background-swap / etc.) — call the same tool, but include a source image in `params`. Hybrid models (nano-banana-pro, gpt-image-2, gemini-2.5-flash-image, seedream-4.5, flux-2-flex, nano-banana-2, gpt-image-1, gpt-image-1.5) flip to image-to-image automatically when `params.imageUrls` is a non-empty array (or `params.imageUrl` is set for single-source models like flux-pro-kontext). Edit-only models (bria-bg-remove, ideogram-character, ideogram-v3-remix/reframe/replace-background, flux-pro-kontext, ideogram-character-remix) only have image-to-image — `params.imageUrls`/`imageUrl` is required. INPUTS: • `model` (required): a model id from `lamina_models_list`. Don't invent it. • `prompt` (required for most models; check `paramSchema.prompt.required` from `lamina_models_describe`; absent from `paramSchema` for prompt-less models like `bria-bg-remove` and `ideogram-v3-reframe`): natural-language brief; ≤2000 chars. • `params` (model-specific): every key MUST be declared in the chosen model's `paramSchema` (call `lamina_models_describe` first). Unknown keys are rejected with a structured `invalid_params` error; each error has `field` + `allowed`/`range`/`got` so you can correct on retry. Omitted optional keys fall back to schema defaults. • `webhookUrl` (optional): HTTPS URL. On terminal status Lamina POSTs `{runId, status, model, prompt, resolvedParams, output, errorMessage, completedAt}` HMAC-signed. RESPONSE: `{runId, status: "queued"|"completed", model, mode, prompt, resolvedParams}`. `mode` is the resolved value ("text-to-image" | "image-to-image"). The `runId` is the fal_request_id — pass it to `lamina_status`. SYNC vs ASYNC: identical contract. Vertex-backed models (`imagen-4.0-*`, `gemini-2.5-flash-image`) complete in seconds and return `status: "completed"` on the first poll. fal-backed models queue and take 5–60s. `lamina_status({ wait: true })` handles both transparently. ERROR HANDLING: validation failures return `code` + `details.errors[]` with `field` + `error` + `allowed`/`range`/`got`. Common codes: `model_not_supported`, `mode_not_supported`, `invalid_params`, `dispatch_failed`.
Dispatch a single atomic video generation. Sibling of `lamina_generate_image` — same shape, but outputs a video URL. WORKFLOW: (1) `lamina_models_list({ modality: "video" })` → pick a model. (2) `lamina_models_describe({ modelId })` → read its flat `paramSchema` to learn required inputs. (3) `lamina_generate_video({ model, prompt, params })` → dispatch, get runId. (4) `lamina_status({ runId, wait: true })` → poll until completed; the response has `output.url`. ONE TOOL, EVERY VIDEO OPERATION. Model id selects the operation; `params` matches the model's paramSchema: • Text-to-video — Kling t2v variants, Wan-2.6-text-to-video, Wan-turbo, Minimax, Seedance t2v, Veo3-text-to-video. Just `prompt` (+ duration / aspectRatio / etc. per the model). • Image-to-video — Kling i2v variants, Wan-2.6/turbo image-to-video, Minimax i2v, Seedance i2v (uses `startImageUrl`), `happy-horse-image-to-video`, `veo3-image-to-video` (sync). `params` includes `imageUrl` (or `startImageUrl` for Seedance, `firstFrameUrl` for Veo3 first-frame). • Keyframe — `veo3-keyframe-to-video` (sync). `params` requires `firstFrameUrl` AND `lastFrameUrl` — model interpolates between them. • Motion-control — `kling-v26-motion-control`, `kling-v26-motion-control-pro`. `params` requires `imageUrl` (character) AND `videoUrl` (motion reference). • Video-to-video (edit) — `wan-video-to-video`, Kling v2v variants. `params` requires `videoUrl` (source). • Reference-to-video — Kling/Seedance/Wan reference variants. `params` uses `referenceImageUrls`. INPUTS: • `model` (required): a model id from `lamina_models_list({modality:"video"})`. • `prompt`: most models require it; some (motion-control variants) are optional. Check `paramSchema.prompt.required` from `lamina_models_describe`. Some models omit `prompt` from `paramSchema` entirely (prompt-less). • `params`: model-specific fields per the model's `paramSchema`. Required URL fields vary by operation — see list above. • `webhookUrl` (optional): HTTPS URL for HMAC-signed completion POST. RESPONSE: `{runId, status: "queued"|"completed", model, mode, prompt, resolvedParams}`. `mode` is the resolved operation. Pass `runId` to `lamina_status`. SYNC vs ASYNC: identical contract. Veo3 variants (`veo3-text-to-video`, `veo3-image-to-video`, `veo3-first-frame-to-video`, `veo3-keyframe-to-video`) are Vertex-backed and complete in seconds. fal-backed models queue and take 30s–5min. `lamina_status({ wait: true, timeoutSeconds: 240 })` handles either transparently. ERROR HANDLING: same shape as `lamina_generate_image` — `code` + `details.errors[]` with `field` + `allowed`/`range`/`got`.
Load the brand context the user has configured for this workspace — voice, visual identity, guardrails, prompt directives, performance patterns. Call this when the user mentions branding, voice, or guardrails, or when you want to weave brand-aware language into `inputs` for `lamina_run`. Returns three independent sections (each can be `null` or empty): - `brandDna` — voice, visual identity, content pillars, audience signals, guardrails. Populated when the workspace has both a brand profile filled in AND brand-DNA synthesis has run. - `guidance` — workflow-scoped prompt directives, negative prompts, recommended moves. Populated by content scoring / recommendation jobs. - `topPatterns` — top-performing patterns aggregated from this workspace's run history. Populated by content scoring runs (look at `topPatterns.itemCount` — `0` means no scored content yet). If a section is `null` (or `topPatterns.itemCount === 0`), the user hasn't configured that piece yet. **Do not fabricate brand attributes.** Tell the user honestly: "I don't see a brand profile / content history configured for your workspace — you can add one in your Lamina workspace settings to get brand-aware suggestions. For now I'll proceed with what you've supplied directly." Then continue with the task using only the user's stated inputs. When sections are populated, fold the relevant strings into the `inputs` you build for `lamina_run` — voice cues into text fields, guardrails into negative prompts, winning patterns as suggestions you can offer the user.
Get a pre-signed upload URL for one user-supplied asset (image, video, or audio). Use this when the user provides a local file you need to feed into `lamina_run` (or `lamina_create.inputs`) as a URL parameter (e.g. `your_photo_image_url`, `product_image_url`, `brand_logo_url`). How to use: - Pass `filename` (the name to register, e.g. "selfie.jpg") and `mediaType` ("image" | "video" | "audio"). - This tool returns `{ uploadUrl, assetUrl, contentTypeHint }`. The `uploadUrl` is a pre-signed PUT URL; the `assetUrl` is what you eventually pass to `lamina_run` (or pre-supply in `lamina_create.inputs`). - THE BYTES DO NOT GO THROUGH THIS TOOL CALL. After this returns, perform an HTTP PUT of the file bytes directly to `uploadUrl` with the `Content-Type` header set to `contentTypeHint` (or override). When the PUT completes (200), the asset is live at `assetUrl`. If your host has shell access (Claude Code, Cursor): execute `curl -X PUT --data-binary @<local-path> -H 'Content-Type: <contentTypeHint>' '<uploadUrl>'` to upload, then call `lamina_run` with `assetUrl` in the relevant input (or pre-supply it to `lamina_create.inputs` so the router doesn't re-ask). If your host doesn't have shell access (Claude Desktop, Claude.ai, ChatGPT): tell the user honestly that you cannot move the bytes from your context to Lamina's storage, and ask them to provide a publicly-reachable URL of the asset (or upload via the Lamina CLI / SDK from a shell), then continue with that URL. Asset URLs returned here are stable and can be reused across multiple runs. There is no need to re-upload between dispatches of related runs.
Cancel a queued or running execution by `runId`. Idempotent — if the run already reached a terminal state (completed / failed / cancelled), the server returns its current status without erroring. Use this when the user changes their mind mid-flight (wrong inputs after dispatch, oversized variant set, abandoned long-running job). Stopping `lamina_status` polls does NOT cancel a run — the orchestrator keeps spending credits until the workflow terminates on its own.
Plan a creative run from a free-text brief. The router agent searches the catalog, picks the best-fit app by CAPABILITY ENVELOPE (an app whose `outputs[]` can deliver the brief, even when broader than asked — narrow via output selection), drafts inputs from the brief, and surfaces every choice the human still needs to make. NEVER dispatches a run — that's `lamina_run`'s job. Branch on `data.status`: • `"plan"` (mode `"app"`): the router committed to an app. Response includes `selectedApp.appId`, `draftedInputs`, optional `selectedOutputs` (output-label subset), and `askUser[]` (per-parameter questions the human must answer). The `askUser` list is the WORKHORSE — it covers everything the human needs to decide on the chosen app: USER-OWNED slots (product photo, brand logo, headshot), PRESET option picks (background style, aesthetic, mood-board references — curated option labels are listed INLINE in the question text), output subsetting (when the entry is `{ name: "__outputs", question }`, the answer is a comma-separated list of output labels), and any KNOB the user needs to choose. To dispatch: ask the human each `askUser[i].question` in chat, collect answers, then call `lamina_run` with `appId: selectedApp.appId`, `inputs: {…draftedInputs, …<answers keyed by askUser[i].name>}`, and `outputs: <selectedOutputs OR the labels parsed from the __outputs answer>`. ONE dispatch round. • `"needs_clarification"`: the router could not commit to an app because the brief is genuinely ambiguous between two or more apps (e.g. banner vs. reel vs. video, single hero vs. multi-language adapts). This is PRE-COMMIT ROUTING ambiguity only. Response includes `clarifications: [{ question }]`. Ask the human each clarification, fold the answers into a refined brief, then call `lamina_create` again. This is the ONLY status where re-calling `lamina_create` with a refined brief is correct. • `"unmatched"`: no pre-built app fits. Response includes `reason`, and — when the brief is a buildable creative request (no catalog app matched) — a `suggestion` object `{ tool: "lamina_generate_workflow", instruction }`. If `suggestion` is present, offer to BUILD a bespoke app: call `lamina_generate_workflow` with the given `instruction`, then `lamina_run` the returned `appId`. If there is no `suggestion`, the brief is outside Lamina's creative-media surface — tell the human and do not retry. ANTI-DRIFT: After `lamina_create` returns `"plan"`, NEVER re-call `lamina_create` to resolve `askUser` items — that re-rolls the LLM and may pick a different app or drop the partial plan. Resolve asks via `lamina_run` with the answers folded into `inputs`/`outputs`. Re-calling `lamina_create` is ONLY correct when the prior response was `"needs_clarification"`, in which case fold the human's clarification answers into a REFINED BRIEF and call `lamina_create` again. The user has NO form UI — they only see what you (the calling LLM) tell them in chat. Treat every `askUser` entry as a question to surface to the human verbatim, including the inline option lists for PRESET choices (so the human knows what they can pick) and the output labels for `__outputs` asks (so they know which deliverables are available). The router never silently uses demo defaults on user-owned slots — that's why those slots appear in `askUser`. Always collect answers first, then dispatch via `lamina_run`.
Generate a BRAND-NEW Lamina app from a plain-language instruction, OR EDIT an existing generated app in place. Use this when NO existing app fits the goal (check `lamina_discover` first) and the user wants a bespoke workflow — or when a follow-up needs the app itself changed (add a step, new output, swap a model), not just a different run. A headless Claude planner assembles a validated node graph from the Lamina node catalog and auto-publishes it as a PRIVATE, immediately-runnable app. - `instruction`: describe what the app should create (or, in edit mode, the change to make), including the inputs the user will provide and the desired output(s). - `baseAppId` (optional): EDIT MODE. The appId of a generated app to modify. The planner starts from its current graph and applies `instruction` as a targeted edit — keeping everything it does not touch — then updates that SAME app in place (same appId, run history preserved). Requires you to be the app creator or a workspace owner/admin. Omit to build a new app. - `ops` (optional, EDIT MODE — the CHEAP path): when you already know the exact change and can express it as a small op list, pass `ops` instead of `instruction` — the server applies them deterministically with NO planner LLM call and no credit charge. Each op is one of: `{op:"setNodeData",nodeId,data}`, `{op:"addNode",node:{id,type,data?}}`, `{op:"removeNode",nodeId}`, `{op:"addEdge",edge:{source,target,sourceHandle?,targetHandle?}}`, `{op:"removeEdge",source,target}`, `{op:"addParameter",parameter:{key,name,type,targetNodeId,targetField,...}}`, `{op:"removeParameter",key}`, `{op:"setParameter",key,patch}`. Requires `baseAppId`. Read the app first (`lamina_describe`/`GET /v1/apps/{id}`) to get node ids. Use `instruction` (planner) for anything you cannot express as ops. - `name` (optional): preferred app name. - `visibility` (optional): `private` (default), `shared` (whole workspace), or `public`. Ignored in edit mode. - `brandProfileId` (optional): bake a brand's voice/visual/guardrails into the app so it's on-brand by default. Omit to use the workspace's active brand. - Returns `{ appId, name, parameters[], outputs[], runUrl }`. In edit mode `appId` is unchanged. Feed `appId` + the returned parameter `key`s straight into `lamina_run` — the parameter set may have changed, so re-read `parameters[]`. - On failure returns `{ error, details[] }` where details are the validation problems the planner could not resolve.
List a generated app's saved graph versions, or restore it to one. Every `lamina_generate_workflow` edit snapshots the app's prior graph first, so a bad edit is always recoverable. - `appId` (required): the generated app. - Omit `restore` to LIST versions — returns `{ versions: [{ version, createdAt, createdBy, changeSummary }] }`, newest first. - Pass `restore: <version>` to RESTORE that version — swaps its graph + parameters back in (the current graph is snapshotted first, so restore is itself undoable). Returns `{ appId, restoredFrom, newVersion }`. Requires you to be the app creator or a workspace owner/admin.
Change an app's reach: `private` (creator/workspace-owner only), `shared` (any workspace member — discoverable via `lamina_discover`), or `public`. Only the app creator or a workspace owner may change visibility. Useful right after `lamina_generate_workflow` to share a freshly generated app.
Create or update this workspace's brand and ground it with a starter Brand DNA, so generated apps and `applyBrand` runs produce on-brand output. Use it to make a fresh workspace on-brand before generating. - `brandName` (required): the brand to create, or the display name when updating. - `brandProfileId` (optional): update an existing profile instead of creating one. Omit to create. - `guardrails` (optional): things to avoid — these become the brand's negatives on visual generation. - `brandVoice` / `visualStyle` / `targetAudience` / `description` / `industry` (optional): shape the brand. - Returns `{ brandProfileId, reused }`. Pass that `brandProfileId` to `lamina_generate_workflow` or `lamina_run` (with `applyBrand`). - Requires an owner/admin identity. Read the current brand with `lamina_brand`.
Give an on/off-brand verdict on a completed run, closing the loop so the next generation respects it. A `reject` with a `note` turns the reason into a brand guardrail — which then flows into `lamina_generate_workflow` and `applyBrand` runs as a negative, so the same off-brand result is avoided. `approve` is acknowledged without changing the brand. - `runId` (required): a run you started (from `lamina_run` / `lamina_status`). - `verdict` (required): `approve` or `reject`. - `note` (optional but recommended on reject): why it is off-brand — this becomes the guardrail. - `brandProfileId` (optional): target brand. Defaults to the run's app brand. - Returns `{ brandProfileId, verdict, applied, guardrails }`. Requires an owner/admin identity.
Read the Brand Guard result a run recorded — the per-node on/off-brand status and score against the workspace brand. Use it to drive the approve/reject turn: after a run, show the output alongside this compliance read, ask the user to approve or reject, and on a reject call `lamina_brand_feedback` (which turns the reason into a guardrail the next generation avoids). - `runId` (required): a run you started (from `lamina_run` / `lamina_status`). - Returns `{ enabled, brandProfileId, nodes[] }`. Each node has `{ nodeId, status, overallScore, brandDeviations, checkedAt }`. `enabled: false` means Brand Guard was off for that app — use `lamina_brand_score` to score it on demand instead.
Score how on-brand a completed run's image output is, and get back the specific deviations — before you show it to the user or decide whether to regenerate. Works on ANY completed run, whether or not Brand Guard was enabled on the app. - `runId` (required): a completed run (from `lamina_run` / `lamina_status`). - `brandProfileId` (optional): brand to score against. Defaults to the run's app brand. - Returns `{ brandFit, dimensions, deviations, suggestions }`. `brandFit` is 0–100; `deviations` lists the specific guideline breaks; `suggestions` is how to fix them. - Use it as the check in a generate → score → refine loop: if `brandFit` is below your bar, feed `deviations`/`suggestions` back into the next generation.
Automatically improve a completed run until it's on-brand — without letting it run away on cost. Repeats score → refine (re-rolling with the specific deviations fed back in) and stops the instant the score clears your bar, the iteration cap is hit, or the credit budget would be exceeded — whichever comes first. Returns the best result plus exactly how many iterations and credits it took. - `runId` (required): a completed run to improve. - `minScore` (optional, default 80): stop once `brandFit` reaches this (0–100). - `maxIterations` (optional, default 3): most refine passes to try (1–10). - `maxCredits` (optional, default 200): hard credit ceiling — never exceeded. - `brandProfileId` (optional): brand to score against. Defaults to the run's app brand. - Returns `{ best, iterations, creditsSpent, stoppedBecause, attempts }`. `best.imageUrl` is the highest-scoring result; `stoppedBecause` is `met_score` | `max_iterations` | `budget` | `no_output`.
Check the workspace's credit balance and the credit packages available to buy — so you can tell the user what they have and what a top-up would cost before running anything expensive. - Returns `{ balance, packages[] }`. Each package has `{ packageId, name, credits, priceCents, currency }`. - To buy one, hand the `packageId` to `lamina_topup`.
Start a credit top-up and get back a Stripe-hosted checkout link to give the user. Use this when the balance is too low to run what they asked for — no need to send them to a dashboard. - `packageId` (required): from `lamina_credits`. - Returns `{ checkoutUrl, credits, amountCents, currency }`. Give the user the `checkoutUrl` to pay; once they do, the credits land on the workspace and you can retry the run. - Never ask the user for card details — they pay on the Stripe page the link opens.
Overview
What is Lamina?
Lamina is a remote MCP server that gives your agent on-brand product video & image generation. Point it at a brief and a brand kit and it returns finished product photos, video reels, and campaign ready banners -> brand guardrails (colors, fonts, tone, style) enforced automatically, no prompt engineering.
Who it is for
- Developers wiring generative media into an app or agent — one endpoint, 14 typed tools, Bearer-token auth.
- Marketers in Claude Code — describe the shot in plain language and get campaign-ready, on-brand creative back. No design tool, no photoshoot.
Tools
lamina_brand— pull the workspace brand guidelineslamina_run— generate: product_shoot, vertical_reel, ad_variant, virtual_try_on, campaign_banner, brand_filmlamina_status— poll a job to completion
~12s per asset · 35+ variants per product · multi-channel auto-formatting.
Quickstart
npx add-mcp https://app.uselamina.ai/mcp/agent
Get an API key at https://app.uselamina.ai/developers. Works with Claude, Claude Code, Cursor, Windsurf, VS Code, Zed, Raycast, n8n, and Zapier. Free to start.
Frequently asked questions
What is the Lamina — On-brand product photos, video & try-ons remote MCP server?
The Lamina — On-brand product photos, video & try-ons remote MCP server is a hosted Model Context Protocol endpoint at https://app.uselamina.ai/mcp/agent, so AI assistants can connect to it without installing or running anything locally.
How do I connect to the Lamina — On-brand product photos, video & try-ons MCP server?
Add the endpoint https://app.uselamina.ai/mcp/agent to any MCP-compatible client such as Claude Code, Cursor, or VS Code. The setup snippets on this page configure each client in one step.
Does the Lamina — On-brand product photos, video & try-ons MCP server require authentication?
Yes. Lamina — On-brand product photos, video & try-ons requires an API key — check the official documentation for how to obtain one, then include it in your client's configuration.
Which transport does the Lamina — On-brand product photos, video & try-ons MCP server use?
Lamina — On-brand product photos, video & try-ons exposes a Streamable HTTP endpoint, the transport used by remote MCP servers and supported by all major MCP clients.
Basic information
Transport
Streamable HTTP
Authentication
API Key
Category
Media & Design
Author
Lamina
Submitted by
Barada Sahu
More remote MCP servers
AdisInsight
Pharmaceutical drug & clinical trial intelligence
AWS Marketplace
Discover, evaluate, and buy solutions for the cloud
Airtable
Bring your structured data to Claude
AgentCouch
Messaging rooms for AI agents: hand off context across tools, worktrees, machines, and teammates. Agents meet in shared rooms over MCP, hand off directly, and leave a replayable transcript; live sessions wake on reply, b
Alice Flights
Real-time flight search for Claude and any MCP client. Ask for flights by origin, destination, dates, passengers, and cabin class — results come back categorized as best, cheapest, and fastest, each with price, full itin
Comments