Tools reference
All 24 MCP tools the Brand Stack connector exposes, with inputs, outputs, and example agent prompts.
The Brand Stack MCP server exposes 24 tools: 14 read tools, 3 image intake tools, 3 generation tools, 2 repo tools (adoption and update proposals), 1 asset-role tool, and 1 distribution tool (the install command). Tools are filtered by your token’s scopes, so read-only tokens see only the read tools.
The definitions come from the same tool registry
(@brandstack/tools-engine) that powers the workspace CLI commands, so
npx @brandstack/cli list-brands and the MCP list_brands tool are
the same server code with the same inputs, rules, and error messages.
Only the transport differs. Authenticate the CLI with an
API key; MCP connectors use OAuth. Both hit
POST /api/mcp, where scopes, credits, and rate limits are enforced
once, server-side, for every caller.
Read tools (mcp:read)
list_brands
List the workspace’s brands, newest first — both kinds: brand
stacks (kind: "brand_stack" — created by adopt_repo or the app’s
stack builder, each carrying a live status) and brand profiles
(kind: "brand_profile" — the older scraped-site records). Either
kind’s id resolves through get_brand.
Inputs: search (case-insensitive name filter) and limit (default
50, max 200). Returns { brands, total, note? } — the note appears
when rows were cut, so an agent knows to narrow with search rather
than concluding an entry does not exist.
“Show me all my brands.”
get_brand
Fetch a single brand by id — either kind:
- A brand profile id (from
list_brands) returns the full record;formatcontrols the output. - A brand stack id or slug (from an
adopt_reporesponse, alist_brandsentry of kindbrand_stack, or a product’sbrandStackId) returns the stack’s live state:status(queued | generating | ready | failed | needs_input), per-sectionprogress,stackUrl, and — once the pipeline has created them —productIdandpersonas, the forward references forlist_personas_for_productand the generation tools.
This is the poll after adopt_repo: call it with the returned
brandStackId every 15–20 seconds until status is ready
(typically 60–90 seconds).
Profile format options:
| Format | What it returns |
|---|---|
json (default) |
Structured fields: colors, typography, voice, messaging, visual direction. |
markdown |
A printable style-guide doc. |
css |
CSS custom properties (--brand-primary, --brand-text, and so on). |
tailwind |
A Tailwind config snippet that extends your theme.colors. |
context |
A prompt-ready summary you can paste into a system prompt. |
Inputs: brand_id (profile UUID, or stack UUID or slug; required), format (optional; profiles only — a stack answers with structured json and points at get_install_command for exports).
“Get my Acme brand as a Tailwind config.”
list_products
List the workspace’s products, newest first, with name, industry, target audience, and lifecycle stage. Each entry also carries brandStackId when the product belongs to a brand stack — the id create_mockup and create_scene accept as brand for explicit attribution.
Inputs: search (case-insensitive name filter) and limit (default 50, max 200). Returns { products, total, note? }. In a workspace full of demo brands, pass search with the product or repo name instead of paging the whole list.
get_product
Fetch a single product. Inputs: product_id (required).
list_personas_for_product
List every persona linked to a product. Returns compact summaries; use get_persona for the full record. Inputs: product_id (required).
“Who are the personas for my Operator product?”
get_persona
Fetch a single persona: demographics, goals, pain points, the generated long-form profile as Markdown (profileMarkdown), absolute image URLs (profileImageUrl, environmentImageUrl, safe to fetch or embed directly), and the id of the first linked product. Inputs: persona_id (required).
list_projects
List every project (a collection of related documents), with id, name, emoji, and timestamps. No inputs.
list_documents
List documents, paginated. Inputs:
limit(1 to 100, default 50)offset(default 0)
Returns { documents, total, limit, offset }.
get_document
Fetch a single document. The body comes back as Markdown (contentMarkdown); documents authored before the editor moved to Markdown are converted on read. Inputs: document_id (required).
“Read me the latest Q4 strategy doc.”
list_assets
Search the workspace’s image library with optional filters:
| Input | What it does |
|---|---|
asset_type |
image, logo, or avatar |
source_type |
mockup_generated, scene_generated, persona_profile, persona_environment, brand_logo_generated, brand_logo_external, attachment, upload |
product_name |
Filter by product (exact match) |
search |
Substring search across source_name and filename |
cursor |
Pass the previous page’s last createdAt for pagination |
limit |
1 to 100, default 40 |
Returns { assets, nextCursor }. Use nextCursor as the next call’s cursor to paginate. Screenshots that arrive through capture_screenshot, the CLI upload, or an upload link live in their own timeline — see list_screenshots.
“Find all the mockup-generated images for the Acme product.”
list_screenshots
Browse the workspace’s Screens timeline (the Screens page in the workspace sidebar) — where every screenshot arriving through capture_screenshot, npx @brandstack/cli upload, or an upload link lands, newest first. Each entry carries the hosted url (pass it to create_mockup as screenshot_url), title, brandName / brandStackId, productName, deviceCategory, sourceUrl (the captured page), captureSource, dimensions, and createdAt.
| Input | What it does |
|---|---|
brand_stack_id |
Filter by attributed brand stack (UUID), or "none" for unattributed |
device_category |
mobile, laptop, or desktop |
capture_source |
capture, upload, upload_link, or manual |
since |
Only screenshots created at or after this ISO timestamp |
search |
Substring search across title, filename, and source URL |
cursor |
Pass the previous page’s last createdAt for pagination |
limit |
1 to 100, default 40 |
Returns { screenshots, nextCursor }.
“Show me the mobile screenshots we captured this week.”
list_templates
List the workspace’s saved setups: reusable compositions (device, camera, atmosphere, aspect ratio) captured from a previous mockup. Completed setups only, newest first. Each entry carries the id you pass to create_mockup as template_id, plus title, deviceType, cameraPosition, cameraLens, atmosphere, aspectRatio, outputUrl, and tags.
Ids are UUIDs on rows you saved, so this is the only way to discover one. title is nullable; describe an untitled setup by its device and lighting.
Inputs: limit (default 50, max 100), search (matches the title).
“What saved mockup setups do I have?”
get_credits
Return the workspace’s remaining credits, split between subscription plan and one-time packs, plus mockupCosts (the live per-tier prices: what a 1K, 2K, or 4K image costs in credits) and manageCreditsUrl (the workspace’s subscription page, where credits are bought). No inputs.
Agents are instructed to call this before a session’s first generation and to quote the chosen tier’s cost, so credits are never spent silently. Purchases can’t happen through the connection itself; when the balance runs low, the agent shares manageCreditsUrl and the user upgrades or buys a pack in the browser.
This is also where a newly connected workspace’s welcome lands: the first call from a workspace that has never used the connector grants credits sized to 10 free mockups, and the response carries a welcome note saying so.
get_brand_asset
Look up the asset filling a brand stack role — “the hero image”,
“the logo”, “the OG card” — and get a URL back. Built-in roles
(logo, favicon, og) resolve from what the pipeline maintains;
named roles (hero, banner, social-card, icon, illustration,
background, pattern, photo, screenshot, product-shot,
email-header) resolve from assets promoted with
set_brand_asset_role. An unfilled role answers with which roles
are filled. Inputs: role (required), brand (optional — defaults
to the workspace’s default stack).
“Use our hero image on this landing page.”
Image intake (mcp:write, no credits)
The generation tools take reference images as public https URLs the server fetches. These three tools, plus the CLI upload, are how an image gets one. None of them cost credits.
capture_screenshot
Capture a screenshot of a public web page on Brand Stack’s own servers and store it in the workspace library. This is the no-shell path: paste a URL in Claude’s chat or Cowork and the agent has a hosted screenshot in one call.
Inputs:
url(required): public http(s) address. A local dev server (localhost, private networks) is not reachable from Brand Stack’s servers; capture those with Playwright, then upload the file throughcreate_upload_link(or the CLI, if a key is configured).viewport(optional):desktop(1440×900, for MacBook and Studio Display mockups, the default) ormobile(390×844 at 2x, for iPhone mockups).full_page(optional, default false): capture the whole scrollable page. Keep it false for device mockups; a device screen shows one viewport.
Returns { url, width, height, assetId, deviceHint }. Pass url to create_mockup as screenshot_url. Takes 5 to 15 seconds.
“Capture mysite.com at a mobile viewport and make it an iPhone mockup.”
create_upload_link
Mint a 30-minute upload channel into the workspace, no login and no API key on either of its two routes:
-
uploadUrl: a browser page where a person drops an image. The pasted-image path for clients with no shell: the user pasted a screenshot into the chat, the agent cannot move the bytes itself, so it sends the user this link and picks the upload back up fromlist_screenshots(newest first). -
uploadEndpoint: accepts the raw file bytes by POST, for agents that do have a shell but no CLI key:curl -X POST -H "content-type: image/png" -H "x-filename: shot.png" \ --data-binary @shot.png "$UPLOAD_ENDPOINT"The response carries the hosted
url(pass it asscreenshot_url) pluswidthandheight, which is what device inference runs on. No user step at all.
No inputs. Returns { uploadUrl, uploadEndpoint, validForMinutes, expiresAt }.
If the POST to uploadEndpoint fails with a 403 or policy error from a
proxy, your agent is running in a sandbox whose network allowlist blocks
brandstack.dev while MCP calls go through their own channel. Fall back
to upload_screenshot below, or add brandstack.dev to the allowlist.
upload_screenshot
Upload a screenshot by passing its bytes base64-encoded inside the
tool call. This is the fallback for sandboxed agent runtimes (Claude
Code on the web, restricted CI) where general HTTP egress runs through
an allowlist: the POST to create_upload_link’s uploadEndpoint dies
with a 403 from the proxy, but MCP tool calls ride a separate channel
that works. This tool moves the bytes over that channel.
Prefer the POST route whenever it works: base64 inside a tool argument passes through the model’s context window, costing roughly 35K tokens per 100KB of image. Before falling back, make the file small (downscale, or re-encode as JPEG/WebP around quality 80; a UI screenshot rarely needs more than ~200KB). The decoded limit is 3MB; the POST route accepts 5MB.
Inputs:
data_base64(required): the image file’s bytes, base64-encoded (base64 -w0 shot.png). Adata:URI prefix and base64url both work; the type is detected from the bytes (PNG, JPEG, WebP, GIF).filename(optional): the original filename, used for the stored name and the timeline title.brand(optional): brand stack UUID, ornone.device(optional):mobile,laptop, ordesktop; inferred from the image’s dimensions when omitted.source_url(optional): the page the screenshot shows (the localhost or preview URL it was captured from).
Returns the same shape as the upload endpoint: { url, width, height, screenshotId, deviceCategory, brandName, filename }. Pass url to
create_mockup as screenshot_url. The screenshot lands in the Screens
timeline like every other intake route.
“The upload POST got blocked by the sandbox proxy — compress the screenshot and send it through upload_screenshot instead.”
Uploading from a shell with the CLI
With an API key configured (npx @brandstack/cli login once, or BRANDSTACK_API_KEY), the CLI does the shell route in one command:
npx @brandstack/cli upload ./shot.png
prints the hosted URL plus the image’s width×height. Every --*-url flag on the CLI’s create-mockup also accepts a local path directly and uploads it first. Optional: an agent without a key uses create_upload_link and loses nothing but the shortcut. See Screenshots → mockups for the full flow.
Generation tools (mcp:write, consume credits)
All three tools consume credits from the connected workspace (a new workspace’s first 10 mockups are free). Generation typically takes 20 to 60 seconds and the call returns synchronously with the final image URL.
All three tools accept an idempotency_key (8 to 128 characters): agents pass a fresh unique value per intended image and reuse the same value when retrying after a timeout or dropped connection. If the earlier attempt completed, its result comes back marked replayed: true and no credits are spent again.
create_mockup
Generate a product mockup: a device, photographed in a real environment, with your screenshot on its screen. At least one of persona_id, template_id, device_type, screenshot_url, atmosphere, camera_position, or custom_instructions must be provided.
The tool’s description teaches the agent to infer before asking. The screenshot’s own dimensions answer the device question (portrait means iPhone with no question; landscape earns exactly one, MacBook Pro or Apple Studio Display), the coding session answers the persona question (the agent matches the product it is working on against list_products), and everything else has a sensible default. You get at most one short question, and none if you say “just make it”.
Most-used inputs:
screenshot_url: the image shown on the device screen. Without it the screen content is invented.persona_id: pulls the persona’s demographics and reference imagery automatically.template_id: a saved setup’s UUID fromlist_templates. Applies that setup’s composition and uses its rendered image as the reference, the same as picking it in the studio.device_type/device_label: for examplemacbook_pro,iphone,studio_display.camera_position/camera_lens: for exampleOver the shoulderplus35mm Wide.atmosphere:Natural Light,Studio Lighting,Golden Hour,Moody / Dark,Bright & Minimal,Neon / Vibrant,Outdoor Daylight. Free-form values are accepted.custom_instructions: free-form prompt. Takes precedence over the single-device default, so ask here for extra monitors or devices in shot.style_reference_url: the “make it look like this” image. Its colors, lighting, and mood shape the whole shot; it does not appear on the device screen. When a user pastes two images, the agent routes the UI capture toscreenshot_urland the photographic one here.character_reference_url,previous_output_url: further reference images (a person’s likeness; a previous generation to vary).aspect_ratio:16:9(default),3:2,4:3,1:1,3:4,2:3,9:16.image_size:0.5K,1K(default),2K,4K. Higher tiers cost more credits.brand: brand attribution. Usually omitted — the workspace default applies automatically (the persona’s brand stack when a persona is set, otherwise the most recently used stack, falling back to the most recently created). Pass a brand stack id (fromlist_products’brandStackId) to attribute explicitly, or"none"for an image unrelated to any workspace brand, such as a screenshot of a third-party website.
Returns { mockupId, outputUrl, promptText, viewUrl, creditsRemaining }. viewUrl opens the mockup in the workspace’s studio, so the image is findable later without digging through chat history; creditsRemaining is the balance after the generation, which the agent surfaces when it runs low.
The workspace’s first mockup is guided: when no mockup has ever been generated, the agent offers choices in one message (camera angle, aspect ratio, and image size with each tier’s real cost) so the user learns what is configurable. From the second mockup on it infers instead.
“Turn that screenshot into a MacBook Pro mockup with Natural Light.”
create_scene
Generate a lifestyle scene featuring a persona. persona_id is required. Either pass an environment_type preset or a free-form environment_prompt.
Inputs:
persona_id(required): the subject of the scene.environment_type/environment_label: preset slug plus label.environment_prompt: free-form description; overrides the preset.camera_position/camera_lens,atmosphere,custom_instructions: same as mockup.character_reference_url,style_reference_url,previous_output_url.aspect_ratio,image_size,brand: same as mockup.
Returns { sceneId, outputUrl, promptText, viewUrl, creditsRemaining }. viewUrl links to the workspace’s asset library, where the scene is saved.
“Create a scene of persona <id> in a coffee shop, golden hour lighting, 9 aspect.”
create_template
Generate a reusable mockup template: a screenshot-free device composition (device, camera angle, lighting, and an optional style reference) meant to be saved once and reused. The resulting template’s id (returned here, or from list_templates) becomes create_mockup’s template_id, which applies the same composition — and its rendered look — to future mockups. There is no persona and no screenshot; at least one of device_type, camera_position, atmosphere, style_reference_url, or custom_instructions must be provided.
Inputs:
style_reference_url: a photo or moodboard whose color palette, lighting, and composition the template adopts. When set, an explicitcamera_positionoratmosphereyou also pass is applied as an edit to the reference — e.g.camera_position: "Bird's eye view"changes the reference’s angle while everything else about its framing and mood carries over. Leave both unset to keep the reference’s own angle and lighting untouched.device_type/device_label,camera_position/camera_lens,atmosphere,custom_instructions: same vocabulary ascreate_mockup.previous_output_url: a prior template generation to use as a variation/regeneration starting point.aspect_ratio,image_size,brand: same ascreate_mockup.title: display name for the template. Optional — when omitted, one is derived from the device, camera angle, and lighting, so the row never sits unnamed inlist_templatesor the Template Studio gallery.
Returns { templateId, title, outputUrl, promptText, viewUrl, creditsRemaining }. viewUrl opens the template in the workspace’s Template Studio; the saved row then shows up in list_templates for reuse.
“Save a template for a MacBook Pro shot from a bird’s-eye angle, styled after this moodboard image.”
Repo adoption (mcp:write)
adopt_repo
Adopt the repo an agent is working in as a Brand Stack. The agent
analyzes the codebase first — global styles and design tokens for
colors, font config for typography, landing components and the README
for copy, package.json for the stack — and submits what it
observed as the analysis JSON (the tool description carries the
exact shape; only repo.name is required). Brand Stack detects the
repo’s target profile (framework + styling system) along the way and
registers the repo as a connection on the stack in both modes.
Inputs:
analysis(required): JSON string of repo observations — repo identity, observed colors with their sources, font families, real UI copy, taglines, README excerpt, and raw stack signals.brand: an existing stack’s id or slug. Omit to create a new stack.proposal_title: title for the change proposal (existing-stack mode).
Two modes:
- Without
brand— creates a new brand stack from the analysis. Generation runs in the background (60–90s) and consumes credits like creating a stack in the app. Observed colors, typography, and copy are applied verbatim withrepo-observedprovenance; the model fills the unobserved fields from the repo’s own copy. Returns{ brandStackId, slug, stackUrl, status, next, targetProfile }. Then pollget_brandwith the returnedbrandStackIdevery 15–20 seconds: it reportsstatus(queued | generating | ready | failed) with per-section progress, and once ready it carries the stack’sproductIdandpersonas— the direct route tolist_personas_for_product, no workspace-wide listing needed. - With
brand— files a free change proposal instead: nothing is applied until a workspace member with publish permission reviews it in the app. Returns{ proposalId, reviewUrl, proposedPaths, status, targetProfile }.
“Adopt this repo into Brand Stack — analyze the styles and copy first.”
propose_update
The precise counterpart to adopt_repo for an existing stack: instead
of raw observations, the agent passes changes already in canonical
model terms — it diffed the repo against the pinned brand version and
knows exactly which fields moved.
Inputs:
brand(required): the stack’s id or slug.changes(required): JSON string — an array of{ path, after, before? }canonical model changes (paths root atstrategy,voice,visual_identity, orassets_manifest).repo(required): the proposing repo asowner/name.base_version,title: optional.
Files a free open change proposal and returns
{ proposalId, reviewUrl, proposedPaths }. Nothing is applied until a
workspace member reviews the field-level diff at reviewUrl and
approves — approval applies under provenance precedence and cuts a new
brand version. A new proposal from the same repo supersedes that
repo’s older open proposals.
“The design team retuned our primary color in globals.css — propose that update to the brand stack.”
set_brand_asset_role
Assign a workspace asset a brand role — “make this mockup the hero
image” is one call. Inputs: brand (id or slug), role (a named
role), asset_id (from list_assets / list_screenshots / a
generation result), optional name and use; remove: true demotes.
Single-slot roles replace their holder; collection roles (photo,
illustration, icon, screenshot) append.
Role assignments are model state: a promotion stamps human-edited
provenance and cuts a new brand version, shows in the changelog
under Assets, and ships in every bundle under assets/library/. Free.
“This is our official product shot now — promote it.”
get_install_command
The distribution verb: returns the exact commands to pull a brand stack
into the repo an agent is working in. Inputs (all optional): brand
(id or slug; defaults to the workspace’s stack), profile (a target
profile id — nextjs-tailwind-v4, nextjs-tailwind-v3, tailwind-v4,
tailwind-v3, or css-variables — to compile the bundle for), pin
(a brand version like 1.2.0 for reproducible installs).
Returns downloadUrl, a ready-to-run installCommand (curl + unzip —
authorized by the stack’s share link, so it works in a fresh repo with
no API key), the equivalent npx @brandstack/cli pull command for
keyed/CI use, and the full install prompt the app’s Build panel
shows. Mints the stack’s share link on first use (why it needs
mcp:write); an existing link is reused. Free.
“Install our brand into this repo, compiled for Tailwind v4.”
A typical agent loop
1. capture_screenshot url="https://mysite.com" viewport="desktop"
→ { url, width: 1440, height: 900, deviceHint: "landscape ..." }
2. create_mockup screenshot_url="..." device_type="macbook_pro"
→ { mockupId, outputUrl, promptText }
3. list_assets source_type="mockup_generated" limit=5
→ confirms the new shot appears in the library