Skip to main content
Glama

Tapercraft — VHS Label Maker

Compose a design

compose_design
Read-only

Build a label design and return a URL the user opens to finish it. Designing and previewing are free; exporting a print-ready file requires a membership, so present the URL as a starting point the user completes in their browser. Fields listed in the response as "unsupported" were NOT applied — tell the user rather than reporting them as done. The user's own artwork goes in through images (upload it first with upload_image; needs an API key): images.background covers the whole sheet, images.panels.<key> one panel each (keys from describe_format), images.logo a custom studio logo. decals places catalog stickers / shapes / retro marks (ids from list_decals) or the user's uploads anywhere on the sheet, texts adds free text blocks, style.productionLogos picks the studio marks (style.productionLogoColorize: 'off' keeps their own colours), and layout.hide: ["poster"] clears the cover art — enough to rebuild a specific vintage cover. Without a key, compose from format + content and tell the user to drag images in after opening the URL.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
textNoOverrides for the fetched metadata (video formats only — on audio formats these come back as unsupported). Omit a field to keep the provider value.
styleNo
textsNoFree text blocks placed on the label (the designer's Text tab). x/y are the block's center in percent of the sheet; width is the percent of the sheet width the block spans (text wraps); size is the font size as percent of the sheet height.
decalsNoStickers, graphics, shapes and the user's own images placed on the label. Each entry names a catalog decal by id (list_decals) OR an upload by ref (upload_image; needs the API key). x/y are percent of the sheet (center-anchored; see describe_format → placement for the coordinate space and the size units). Size with `width` (percent of the sheet width) where describe_format accepts it, else `scale`.
formatYesWhich packaging format
imagesNoThe user's own artwork by upload ref (from upload_image). Needs the API key that owns the uploads. Single-surface formats only (describe_format → singleSurface). Each value is a ref string or { ref, fit, opacity }.
layoutNo
contentNoWhat the design is of. Provide a query, or an id from search_content. Video formats take movie/tv; audio formats (cassette, jcard, cd*, vinyl*, minidisc*) take album. For audio, the album alone builds the complete design — cover art, tracklist sides, QR code — and style.font / labelColor / background restyle it.

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed2 schema fields changed
    • addedInput schema / properties / style / properties / productionLogoColor
      Added value: +{
      +  "description": "6-digit hex the studio logos are painted with ('tint' / 'solid'); absent = the label colour.",
      +  "type": "string"
      +}
    • addedInput schema / properties / style / properties / productionLogoColorize
      Added value: +{
      +  "description": "Video formats: how the studio logos (style.productionLogos or the title's own) are painted. 'solid' (the default) fills them flat in the label colour — a full-colour mark like RCA/Columbia becomes a plain shape; 'off' keeps their original colours; 'tint' recolours while keeping shading.",
      +  "enum": [
      +    "off",
      +    "tint",
      +    "solid"
      +  ],
      +  "type": "string"
      +}
  2. Changed1 schema field changed
    • addedInput schema / properties / layout / properties / spine2
      Added value: +{
      +  "additionalProperties": false,
      +  "properties": {
      +    "title": {
      +      "description": "Turns on Dual Spine and gives the second spine its own title: 'text' prints the title as text there, 'logo' paints the provider's wordmark. The first spine keeps style.useLogo / text.title. Formats with a second spine only (slipcover, doublevhs, betamax, compact-tape, bluray-slipcover, cardbox); elsewhere reported unsupported.",
      +      "enum": [
      +        "text",
      +        "logo"
      +      ],
      +      "type": "string"
      +    }
      +  },
      +  "required": [
      +    "title"
      +  ],
      +  "type": "object"
      +}
  3. Changed5 schema fields changed
    • addedInput schema / properties / decals
      Added value: +{
      +  "description": "Stickers, graphics, shapes and the user's own images placed on the label. Each entry names a catalog decal by id (list_decals) OR an upload by ref (upload_image; needs the API key). x/y are percent of the sheet (center-anchored; see describe_format → placement for the coordinate space and the size units). Size with `width` (percent of the sheet width) where describe_format accepts it, else `scale`.",
      +  "items": {
      +    "additionalProperties": false,
      +    "properties": {
      +      "color": {
      +        "description": "6-digit hex for colorize (default: the label colour)",
      +        "type": "string"
      +      },
      +      "colorize": {
      +        "description": "Paint the decal one colour: 'tint' keeps its shading, 'solid' flattens it",
      +        "enum": [
      +          "tint",
      +          "solid"
      +        ],
      +        "type": "string"
      +      },
      +      "id": {
      +        "description": "A decal id from list_decals (e.g. \"rcacolumbia!\", \"04-rounded-rectangle\")",
      +        "type": "string"
      +      },
      +      "layer": {
      +        "description": "'over' (default), 'under' the label's text and pictures, or 'background'",
      +        "enum": [
      +          "over",
      +          "under",
      +          "background"
      +        ],
      +        "type": "string"
      +      },
      +      "ref": {
      +        "description": "An upload ref, instead of id",
      +        "pattern": "^upload:",
      +        "type": "string"
      +      },
      +      "rotation": {
      +        "maximum": 360,
      +        "minimum": -360,
      +        "type": "integer"
      +      },
      +      "scale": {
      +        "description": "The designer's size unit (100 = natural width ÷ 4 layout units); use instead of width",
      +        "maximum": 900,
      +        "minimum": 10,
      +        "type": "integer"
      +      },
      +      "side": {
      +        "description": "Two-sided formats only",
      +        "enum": [
      +          "front",
      +          "back"
      +        ],
      +        "type": "string"
      +      },
      +      "stretch": {
      +        "description": "Horizontal stretch, percent of the natural aspect",
      +        "maximum": 1000,
      +        "minimum": 10,
      +        "type": "integer"
      +      },
      +      "width": {
      +        "description": "Rendered width as percent of the sheet width (formats with placement.decals.layoutWidthUnits)",
      +        "maximum": 200,
      +        "minimum": 1,
      +        "type": "number"
      +      },
      +      "x": {
      +        "description": "Center, percent of the sheet width (default 50)",
      +        "maximum": 100,
      +        "minimum": 0,
      +        "type": "number"
      +      },
      +      "y": {
      +        "description": "Center, percent of the sheet height (default 50)",
      +        "maximum": 100,
      +        "minimum": 0,
      +        "type": "number"
      +      }
      +    },
      +    "type": "object"
      +  },
      +  "maxItems": 24,
      +  "type": "array"
      +}
    • changedInput schema / properties / layout / properties / hide / description
      Previous value: -"Fields to hide on the design"New value: +"Fields to hide on the design (video formats). 'poster' removes the cover art so a panel image or decal can carry the front."
    • changedInput schema / properties / layout / properties / hide / items / enum
      Previous value: -[
      -  "rating",
      -  "texsOrg",
      -  "overview",
      -  "labelOverview",
      -  "fbiWarning",
      -  "rules",
      -  "pullquote",
      -  "pullquoteCredit",
      -  "spineMeta",
      -  "barcode",
      -  "qrCode",
      -  "spineLogo",
      -  "title",
      -  "tagline",
      -  "year",
      -  "origin",
      -  "runtime",
      -  "starring",
      -  "director",
      -  "budget",
      -  "revenue",
      -  "movieId",
      -  "seasonEpisode",
      -  "writers",
      -  "composer",
      -  "producer",
      -  "productionLogos"
      -]New value: +[
      +  "poster",
      +  "rating",
      +  "texsOrg",
      +  "overview",
      +  "labelOverview",
      +  "fbiWarning",
      +  "rules",
      +  "pullquote",
      +  "pullquoteCredit",
      +  "spineMeta",
      +  "barcode",
      +  "qrCode",
      +  "spineLogo",
      +  "title",
      +  "tagline",
      +  "year",
      +  "origin",
      +  "runtime",
      +  "starring",
      +  "director",
      +  "budget",
      +  "revenue",
      +  "movieId",
      +  "seasonEpisode",
      +  "writers",
      +  "composer",
      +  "producer",
      +  "productionLogos"
      +]
    • addedInput schema / properties / style / properties / productionLogos
      Added value: +{
      +  "description": "Video formats: Classic Logo ids (list_decals → classicLogos, e.g. \"rcacolumbia!\") for the spine and studio slot, in order (#1 is the spine). As the whole selection they REPLACE the title's own studio logos; [] removes the studio slot.",
      +  "items": {
      +    "type": "string"
      +  },
      +  "maxItems": 4,
      +  "type": "array"
      +}
    • addedInput schema / properties / texts
      Added value: +{
      +  "description": "Free text blocks placed on the label (the designer's Text tab). x/y are the block's center in percent of the sheet; width is the percent of the sheet width the block spans (text wraps); size is the font size as percent of the sheet height.",
      +  "items": {
      +    "additionalProperties": false,
      +    "properties": {
      +      "align": {
      +        "enum": [
      +          "left",
      +          "center",
      +          "right"
      +        ],
      +        "type": "string"
      +      },
      +      "allCaps": {
      +        "type": "boolean"
      +      },
      +      "color": {
      +        "description": "6-digit hex (default: the label colour)",
      +        "type": "string"
      +      },
      +      "font": {
      +        "description": "Family name — a curated family or any Google font",
      +        "type": "string"
      +      },
      +      "italic": {
      +        "type": "boolean"
      +      },
      +      "letterSpacing": {
      +        "description": "px",
      +        "maximum": 50,
      +        "minimum": -20,
      +        "type": "number"
      +      },
      +      "lineHeight": {
      +        "maximum": 4,
      +        "minimum": 0.5,
      +        "type": "number"
      +      },
      +      "rotation": {
      +        "maximum": 360,
      +        "minimum": -360,
      +        "type": "integer"
      +      },
      +      "side": {
      +        "enum": [
      +          "front",
      +          "back"
      +        ],
      +        "type": "string"
      +      },
      +      "size": {
      +        "description": "Font size, percent of the sheet height (default 9)",
      +        "maximum": 60,
      +        "minimum": 0.5,
      +        "type": "number"
      +      },
      +      "text": {
      +        "description": "The text; newlines allowed",
      +        "type": "string"
      +      },
      +      "weight": {
      +        "maximum": 900,
      +        "minimum": 100,
      +        "type": "integer"
      +      },
      +      "width": {
      +        "description": "Percent of the sheet width (default 50)",
      +        "maximum": 100,
      +        "minimum": 10,
      +        "type": "integer"
      +      },
      +      "x": {
      +        "maximum": 100,
      +        "minimum": 0,
      +        "type": "number"
      +      },
      +      "y": {
      +        "maximum": 100,
      +        "minimum": 0,
      +        "type": "number"
      +      }
      +    },
      +    "required": [
      +      "text"
      +    ],
      +    "type": "object"
      +  },
      +  "maxItems": 24,
      +  "type": "array"
      +}
  4. Changed1 schema field changed
    • addedInput schema / properties / images
      Added value: +{
      +  "additionalProperties": false,
      +  "description": "The user's own artwork by upload ref (from upload_image). Needs the API key that owns the uploads. Single-surface formats only (describe_format → singleSurface). Each value is a ref string or { ref, fit, opacity }.",
      +  "properties": {
      +    "background": {
      +      "description": "One image over the whole sheet (all panels).",
      +      "oneOf": [
      +        {
      +          "pattern": "^upload:",
      +          "type": "string"
      +        },
      +        {
      +          "additionalProperties": false,
      +          "properties": {
      +            "fit": {
      +              "enum": [
      +                "fit",
      +                "fill",
      +                "stretch"
      +              ],
      +              "type": "string"
      +            },
      +            "opacity": {
      +              "maximum": 100,
      +              "minimum": 0,
      +              "type": "number"
      +            },
      +            "ref": {
      +              "type": "string"
      +            }
      +          },
      +          "required": [
      +            "ref"
      +          ],
      +          "type": "object"
      +        }
      +      ]
      +    },
      +    "logo": {
      +      "description": "A custom studio / production logo (video formats). It replaces the title's own studio logos on the spine and back panel. Upload a transparent PNG.",
      +      "pattern": "^upload:",
      +      "type": "string"
      +    },
      +    "panels": {
      +      "additionalProperties": {
      +        "oneOf": [
      +          {
      +            "pattern": "^upload:",
      +            "type": "string"
      +          },
      +          {
      +            "additionalProperties": false,
      +            "properties": {
      +              "fit": {
      +                "enum": [
      +                  "fit",
      +                  "fill",
      +                  "stretch"
      +                ],
      +                "type": "string"
      +              },
      +              "opacity": {
      +                "maximum": 100,
      +                "minimum": 0,
      +                "type": "number"
      +              },
      +              "ref": {
      +                "type": "string"
      +              }
      +            },
      +            "required": [
      +              "ref"
      +            ],
      +            "type": "object"
      +          }
      +        ]
      +      },
      +      "description": "Per-panel images keyed by the panel key describe_format reports (e.g. front, back, spine1). Unknown keys come back as unsupported.",
      +      "type": "object"
      +    }
      +  },
      +  "type": "object"
      +}
  5. Changed1 schema field changed
    • changedInput schema / properties / format / enum
      Previous value: -[
      -  "slipcover",
      -  "side-load-vhs",
      -  "doublevhs",
      -  "betamax",
      -  "compact-tape",
      -  "bluray-cover",
      -  "bluray-slipcover",
      -  "dvd-cover",
      -  "clamshell",
      -  "polycase",
      -  "cardbox",
      -  "disc",
      -  "cassette",
      -  "cassingle",
      -  "jcard",
      -  "cd",
      -  "cd-tray",
      -  "cd-insert",
      -  "vinyl-label",
      -  "vinyl-jacket",
      -  "vinyl-sleeve",
      -  "minidisc-label",
      -  "minidisc-full-labels",
      -  "minidisc-jcard",
      -  "minidisc-cover",
      -  "minidisc-tray"
      -]New value: +[
      +  "slipcover",
      +  "side-load-vhs",
      +  "doublevhs",
      +  "betamax",
      +  "compact-tape",
      +  "bluray-cover",
      +  "bluray-slipcover",
      +  "dvd-cover",
      +  "steelcase",
      +  "clamshell",
      +  "polycase",
      +  "cardbox",
      +  "disc",
      +  "cassette",
      +  "cassingle",
      +  "jcard",
      +  "cd",
      +  "cd-tray",
      +  "cd-insert",
      +  "vinyl-label",
      +  "vinyl-jacket",
      +  "vinyl-sleeve",
      +  "minidisc-label",
      +  "minidisc-full-labels",
      +  "minidisc-jcard",
      +  "minidisc-cover",
      +  "minidisc-tray"
      +]
  6. Changed1 schema field changed
    • changedInput schema / properties / format / enum
      Previous value: -[
      -  "slipcover",
      -  "side-load-vhs",
      -  "doublevhs",
      -  "betamax",
      -  "compact-tape",
      -  "bluray-cover",
      -  "bluray-slipcover",
      -  "dvd-cover",
      -  "clamshell",
      -  "polycase",
      -  "cardbox",
      -  "disc",
      -  "cassette",
      -  "cassingle",
      -  "jcard",
      -  "cd",
      -  "cd-tray",
      -  "cd-insert",
      -  "vinyl-label",
      -  "vinyl-jacket",
      -  "vinyl-sleeve",
      -  "minidisc-label",
      -  "minidisc-cover",
      -  "minidisc-jcard",
      -  "minidisc-tray",
      -  "minidisc-full-labels"
      -]New value: +[
      +  "slipcover",
      +  "side-load-vhs",
      +  "doublevhs",
      +  "betamax",
      +  "compact-tape",
      +  "bluray-cover",
      +  "bluray-slipcover",
      +  "dvd-cover",
      +  "clamshell",
      +  "polycase",
      +  "cardbox",
      +  "disc",
      +  "cassette",
      +  "cassingle",
      +  "jcard",
      +  "cd",
      +  "cd-tray",
      +  "cd-insert",
      +  "vinyl-label",
      +  "vinyl-jacket",
      +  "vinyl-sleeve",
      +  "minidisc-label",
      +  "minidisc-full-labels",
      +  "minidisc-jcard",
      +  "minidisc-cover",
      +  "minidisc-tray"
      +]
  7. Changed1 schema field changed
    • changedInput schema / properties / format / enum
      Previous value: -[
      -  "slipcover",
      -  "side-load-vhs",
      -  "doublevhs",
      -  "betamax",
      -  "bluray-cover",
      -  "bluray-slipcover",
      -  "dvd-cover",
      -  "clamshell",
      -  "polycase",
      -  "cardbox",
      -  "disc",
      -  "cassette",
      -  "cassingle",
      -  "jcard",
      -  "cd",
      -  "cd-tray",
      -  "cd-insert",
      -  "vinyl-label",
      -  "vinyl-jacket",
      -  "vinyl-sleeve",
      -  "minidisc-label",
      -  "minidisc-cover",
      -  "minidisc-jcard",
      -  "minidisc-tray",
      -  "minidisc-full-labels"
      -]New value: +[
      +  "slipcover",
      +  "side-load-vhs",
      +  "doublevhs",
      +  "betamax",
      +  "compact-tape",
      +  "bluray-cover",
      +  "bluray-slipcover",
      +  "dvd-cover",
      +  "clamshell",
      +  "polycase",
      +  "cardbox",
      +  "disc",
      +  "cassette",
      +  "cassingle",
      +  "jcard",
      +  "cd",
      +  "cd-tray",
      +  "cd-insert",
      +  "vinyl-label",
      +  "vinyl-jacket",
      +  "vinyl-sleeve",
      +  "minidisc-label",
      +  "minidisc-cover",
      +  "minidisc-jcard",
      +  "minidisc-tray",
      +  "minidisc-full-labels"
      +]
  8. First observed

TDQS

A4.4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the annotations, it discloses that designing/previewing is free while export is gated, that images require an API key, that unknown panel keys come back as 'unsupported', and instructs the agent to report unsupported fields rather than claim success. That is exactly the operational context annotations (readOnly/openWorld) cannot carry.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Purpose and the URL/export caveat are front-loaded, and nearly every clause carries a concrete instruction rather than filler. It is a single dense paragraph though, with several long appositive lists, so it is heavier than it needs to be for scanning.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For an 8-parameter nested tool with no output schema, the description covers the return value (URL), the gate on export, the API-key dependency, and the unsupported-field contract, plus per-parameter routing. It does not describe anything else the response contains (e.g. the unsupported list shape), which is a minor gap given no output schema exists.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With 75% schema coverage the schema does much of the work, but the description adds real cross-references: which image slot is which (images.background vs panels.<key> vs logo), where decal/text/style.productionLogos and layout.hide fit, and the practical pattern for rebuilding a specific cover. It leaves a few areas (layout.spine2, style.finish, text overrides) to the schema alone.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The first sentence states a specific verb and resource ('Build a label design') plus the distinctive output (a URL the user opens to finish it), which separates it from save_design and export_design by implication. However, it never names those siblings, so the distinction must be inferred from the free-vs-membership note rather than stated outright.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Routes the agent explicitly: upload artwork first with upload_image, get decal ids from list_decals, panel keys from describe_format, and states the fallback path when no API key is available (compose from format + content, tell the user to drag images in later). It also names the alternative outcome (export needs a membership) so the agent knows this tool stops at the URL.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Try in Browser

Glama MCP Gateway

Add one secure layer between your agents and this server.

Resources