Customuse MCP
Customuse is an async, credit-based platform. Every result is a node on a node-editor workflow (a graph at https://customuse.com/workflow/<id>) the user can reopen, tweak and re-run. 16 MCP tools; the real parameter space lives in the node-type catalog, not in the tool schemas.
Completion contract
Done means: the requested asset exists (resultUrl / meshUrl), it is handed to the user together with canvasUrl, the credit cost is stated, and anything the user asked to be saved locally is on disk. A status: "started" response, a created node, or an applied graph edit is not completion. Never end a turn while a node is still generating.
Read what this request needs
| Need |
Reference |
| Tool parameters, response fields, error → recovery |
tools.md |
| Which node type; exact enum, range, handle, precondition |
node-types.md |
| Multi-node pipeline payloads, resume/repair of a broken graph |
recipes.md |
| Writing prompts for generate vs edit vs video motion |
prompting.md |
Read the one that applies. Recipes are alternatives to adapt to the request, not a chain to execute end to end.
Preflight
- Tools appear as
mcp__customuse__<tool>. If missing, the server is not registered for this project directory — tell the user to run there: claude mcp add --transport http customuse https://api.customuse.com/v1/mcp --header "Authorization: Bearer <cmk_live_…>". MCP scope is per project path; a worktree of a registered project does not inherit it.
- The catalog is a mapping, not the database.
references/node-types.md is a dated snapshot; customuse_list_node_types is authoritative and account-gated. On any conflict the tool wins. If the user says a model or node type exists and your memory disagrees, call the tool unfiltered before telling them it doesn't.
- Check
customuse_get_credits_balance before any 3D, video, cascade or autorun run.
Money rules
- Balance is not a price.
customuse_get_credits_balance returns what is left, never what a run costs.
- Measured
chargedCredits 2026-09-20 — the server's "image 10–40 / 3D 55–150" wording is wrong. Images: flux2Image = 2 · gptImage2 1K, flux2ProImage, fluxImg2Img, the four presets = 4 · gemini25FlashImage/Edit, fluxKontextPro, flux2ProEdit, imageOptimize = 6 · nanoBananaLiteImage/Edit, twoDTextures = 7 · gptImage2Edit = 8 · nanoBanana2Image, imageVariations ×2 = 11 · nanoBanana2Edit = 16 (2K default) · clarityUpscaler ×2 = 17 · gemini3ProImage/Edit 1K = 20 · assetExtractor = 21 (on its child) · imageToMultiview = 27 · bgRemoval = 0. 3D: mesh-post stages = 2 each · autoRigging = 33 · textureGeneration 1K = 40 · hi3dV21Mesh3d = 65 · modelTextureGeneration = 70 · tripoV31Mesh3d / tripoP1Mesh3d / customuseCr1Mesh3d / meshyV7Mesh3d / hunyuanV31Mesh3d / roblox3d = 100 · tripoP2Mesh3d = 130 · hi3dV3Mesh3d = 234. Video: seedance20Video 4 s/480p = 37 · kling3Video 3 s/pro = 44 (1920×1080) · seedance25Video 4 s/480p = 54 — price tracks duration × resolution, so "premium" Kling is the cheaper option at short lengths. Uploads and graph edits without a run are free; prices are versioned (pricingVersion) — quote them with the date.
- Exact cost per node =
customuse_get_workflow {includeData: true} → nodes[].data.chargedCredits (reimbursedCredits after a failure). The field is per node type: present on imageToMultiview, absent on imageVariations and its children though the run was billed, and customuse_duplicate_workflow copies it verbatim — fall back to the balance delta there, and never sum across a workflow and its copy. Never report 0 for a node you did not check.
- Work stage by stage inside the scope the user approved. Ask again only before a new kind of charge: first video, first 3D, a cascade over several paid nodes, or an autorun budget.
budgetCredits on customuse_autorun_workflow is a soft cap, checked after a cycle. Measured: budget 10 → spentCredits: 44, status: "budget_exhausted", while the graph held one node worth 7 credits; the rest was the agent's own reasoning, billed on top. Assume a 4–5× overshoot on small budgets, quote that to the user before starting, and prefer building the graph yourself when the balance is tight.
- Never resubmit a paid job. A polling gap, a tool timeout or a lost response does not cancel or lose the remote run: re-poll
customuse_get_workflow and match by node type + prompt. A second customuse_generate is a second charge.
- Reuse before regenerate. "Make a low-poly version of that" means find the existing node and run only the missing step. Lookup order: this conversation →
customuse_get_workflow on the session workflow → customuse_list_workflows → ask, listing the candidates. Stop at the first confident match. Regenerating something that already exists is both a wrong answer and a second charge.
Core loop
customuse_list_node_types # once per session, or when a type id is rejected
customuse_generate {nodeType, prompt, data} # omit workflowId on the FIRST call of the session
→ {workflowId, nodeId, runId, status:"started", canvasUrl}
customuse_get_workflow {workflowId} # poll until terminal
→ nodes[].status: idle | generating | complete | error (in flight is `generating`, not `running`)
→ resultUrl (image/video), meshUrl (3D — `resultUrl` repeats it), previewUrl (often null), error
- Poll schedule: first check at ~3 s, back off ×1.5, cap at 15 s for images and 30 s for video/3D. Stop only on
complete or error; anything else means still running. Measured: image ~15 s, image→mesh cascade ~2 min end to end.
- One workflow per conversation. Omit
workflowId on the first generation, reuse the returned id for everything after. Pass an explicit id only to extend a workflow from customuse_list_workflows.
data merges shallowly onto the type's defaultData — pass only what changes. Same for update_nodes[].data_patch.
- Tool results are a prose line plus a JSON blob: parse the JSON, don't read the prose. Echoed
position is advisory — the server re-lays out nodes.
- Check the run receipt before polling.
customuse_run_nodes answers {runId, tracked_node_ids, skipped_node_ids, status} and returns status: "noop" with runId: null — without isError — when the ids were unknown. status: "started" with a non-empty tracked_node_ids is the only green light; in cascade mode downstream nodes are absent from that list, so poll the graph.
- Values are validated by the provider at run time, not by the tool: an out-of-enum
data value is accepted, stored, and comes back as a node error with the list of legal values (refunded). Prompts shorter than 3 characters fail the same way.
- A node in
error never re-runs. customuse_run_nodes answers started but nothing executes — same generationRunId, same error, no charge — even after an update_nodes data_patch. Delete the node and create a corrected copy instead. Nodes that merely never ran (idle) do re-run normally.
Choosing the approach
| Situation |
Path |
Never |
| One generation (text→image, edit, image→3D, video, Roblox asset) |
customuse_generate |
— |
| Chain of 2+ nodes |
customuse_edit_workflow_graph + run_node_ids + run_mode: "cascade" |
three separate customuse_generate calls |
| Mesh already exists, user wants texture/LOD/UV/rig |
add the post-process node, connect mesh-out → mesh-in, run it |
re-running image→3D |
| Some nodes failed mid-graph |
customuse_run_nodes on the failed nodes + cascade |
re-running the whole graph |
| Hands-off "just make me X", budget-capped |
customuse_autorun_workflow → poll customuse_get_autorun |
spending the whole balance as budget |
| User supplied a reference image |
customuse_upload_media, then connect image-out |
inventing a URL or a mediaId |
Building graphs
customuse_edit_workflow_graph applies create_nodes + connect_nodes + update_nodes + disconnect_nodes + delete_node_ids in one transaction, optionally followed by a run.
- Reference new nodes by a caller-chosen
client_id; the response maps each to its real id. connect_nodes and run_node_ids accept either form.
- Handles are exact catalog ids:
image-out → image-in, mesh-out → mesh-in, prompt-in, texturePrompt-in, start-image-in / end-image-in (video), front|left|right|back-image-in (multiview), target-mesh-in / source-mesh-in (bake), mesh-1-in … mesh-10-in (UV packing).
- Fan-out nodes spawn children when the run starts, already wired parent
image-out → child image-in; the parent's own resultUrl is null or just echoes the source. Child types differ per parent: imageVariations → imageVariationResult (ids in data.outputNodeIds), imageToMultiview → multiviewResult (identify by data.viewLabel), assetExtractor → a single assetExtractorPreview (id in data.previewNodeId). A complete parent does not mean the results are ready: assetExtractor completes in ~5 s with only its analysis (detectedParts), while the child keeps generating for another ~45 s and carries the charge. Always poll the children, via customuse_get_workflow {workflowId, nodeIds:["<parent>"], includeData: true}.
- Wiring a fan-out child into a downstream node is a second, free edit call.
- Unknown types, bad handles, cycles and out-of-plan types are rejected as
invalid_request before anything is charged — fix the shape locally rather than retrying blind.
Reference images
customuse_upload_media takes exactly one of url (public http(s)), base64 (data URI or raw + mimeType), or mediaId from customuse_list_my_media. It costs nothing and returns {nodeId, imageUrl, workflowId, canvasUrl}; the created imageUpload node feeds edit/3D/video nodes from image-out and stays idle with resultUrl: null by design. The url route depends on Customuse's fetcher reaching that host — measured: upload.wikimedia.org returns internal_error twice, the same bytes as base64 succeed, so on internal_error switch route instead of retrying the URL. mediaId covers only images the user added on customuse.com: MCP uploads do not appear in My Media (measured), so reuse one by connecting its existing imageUpload node or re-passing its imageUrl.
Look at the reference before spending on it. Download it and open it; never trust a filename, URL slug, page title or the user's description of what is in it. A file called Toolbox.jpg turned out to be a night shot of a house, and the variations faithfully restyled that house — 11 credits for garbage. If the image cannot be opened, say so and ask rather than wiring it into a paid node. The same applies to anything routed into a 3D node: the reference decides the result, so a wrong or cluttered reference is a wasted mesh charge.
Picking a node type
Ordered defaults — when two could apply, the higher entry wins. Do not downgrade to a model because its parameters look simpler; verify the better one first.
- Text → image:
gptImage2 (4 credits, cleanest subject separation and text) or flux2ProImage (4) for drafts and layouts; nanoBanana2Image (11) when photo-realism matters most; gemini3ProImage for maximum fidelity; nanoBananaLiteImage (7) only when an even cheaper draft is wanted.
- Game-asset concept art with a free alpha background:
gameAsset / vehicle / character / clothingReference (4 each). They rewrite the prompt into a "3D stylized game X, 3/4 front angle, transparent background" template, so camera and background wording is ignored — pick a plain model instead when those matter.
- Edit an existing image (needs
image-in): nanoBanana2Edit; gptImage2Edit for text/typography; fluxKontextPro for style transfer. Several takes of one image: imageVariations.
- Prepare an image for 3D:
imageOptimize (6; white bg, centered, A/T-pose). It is a pass-through: it completes with resultUrl: null and hands the corrected image to whatever pulls its image-out, so there is nothing to show the user from it. Then bgRemoval (free) or clarityUpscaler (17, 1024→2048) only if still needed. Back-side accuracy: imageToMultiview (27) before a multiview mesher.
- Image → textured mesh in one node:
modelTextureGeneration (Customuse CR1) — 70 credits, ~3.5 min, PBR maps in textureMaps (albedo/normal/orm). Cheaper and simpler than tripoV31Mesh3d + textureGeneration (100 + 40).
- Image → geometry only (all untextured, measured at
faceLimit: 12000): meshyV7Mesh3d (100) or tripoP2Mesh3d (130) keep stamped relief on hard-surface props · tripoV31Mesh3d / tripoP1Mesh3d / customuseCr1Mesh3d (100) are smoother and flatten fine detail · hunyuanV31Mesh3d (100) gives the cleanest surface at an exact 40 000 tris · hi3dV21Mesh3d (65) is cheapest but ignores the budget (676 k tris) and hi3dV3Mesh3d (234) is the density option. Hi3D requires faceLimit ≥ 100 000; Hi3D and Hunyuan ship POSITION only, so add meshCleanup (recalculateNormals) + uvUnwrap before texturing. quad: true never survives the GLB export.
- Mesh post (2 credits each unless noted):
meshCleanup, meshDecimation (LOD), uvUnwrap, uvPacking, textureBaking (bakeChannel is an array: all|base-color|normal|roughness|specular|metalness), textureGeneration (retexture, 40), autoRigging (33 — the provider accepts only aquatic|avian|biped|hexapod|octopod|quadruped|serpentine). Tileable PBR maps from a photo: twoDTextures (7) returns baseColorUrl / normalUrl / roughnessUrl / metalnessUrl.
- Roblox deliverable:
roblox3d with the matching generationType (100, ~5 min, comes out textured) — not a generic mesh node.
- Video (all three verified):
seedance20Video (4–15 s, 480p|720p|1080p|4k) = 37 for 4 s @480p · kling3Video (3–15 s, pro|4k) = 44 for 3 s @pro and delivers full 1920×1080 · seedance25Video (4–30 s, mov option) = 54 for 4 s @480p. Match videoInputMode to the wiring and set generateAudio: false unless sound is wanted — it defaults to true on both Seedance nodes. Video nodes expose a poster frame in data.mediaArtifacts.posterUrl / thumbnailUrl, so a still can be shown without downloading the clip.
- Break one object into parts:
assetExtractor (21) — see the fan-out note below; it decomposes a single subject, it does not split a multi-object image.
- Character/NPC model end to end:
character → imageOptimize (aPose) → modelTextureGeneration → autoRigging biped. Measured 113 credits, ~6.5 min, 18 986 tris, 58 joints. The rigged GLB loses the textures — hand over the textured mesh and the rigged file together. See recipes.md recipe 12.
Delivery
- Hand over: the asset URL,
canvasUrl, the workflow id and node ids (they make the next request cheap), the credit cost, and one concrete limitation.
- Save locally only what the user asked for, or when they are clearly working in a repo:
./customuse/<workflow-slug>/<nodeType>-<first8-of-nodeId>.<ext>. Never overwrite an existing file; verify the download is non-empty and of the expected type.
- Open results before describing them. Images: open
resultUrl. 3D: the top-level previewUrl is usually null, but customuse_get_workflow {includeData: true} exposes data.thumbnailUrl — a real render (verified) — so open that; check textureMaps / isPBR for texture presence, and parse the GLB (magic glTF, triangle/vertex counts) only for numbers a render cannot show. A render establishes subject, composition and completeness, never topology, watertightness, UV or rig quality. Never imply you inspected something you did not open.
- Keep chat clean: polling is silent (a status change is worth a line, individual polls are not), no raw node/run ids, no tool names, no JSON dumps unless the user asks.
Errors
isError: true responses carry structuredContent.error.code: invalid_request (bad node type, non-existent handle — the message lists the valid ones, graph cycle, two upload sources), not_found (well-formed but unknown workflow or autorun session), not_enough_credits (stop, tell the user to top up at customuse.com — never retry in a loop), internal_error (server-side; for an upload switch route, otherwise one retry then report). Nothing is charged for any of them. Malformed arguments fail earlier still, as MCP error -32602: Input validation error with no code. A node ending status: "error" is not a tool error: it is refunded automatically (reimbursedCredits); read nodes[].error — provider messages name the offending field — before retrying with different inputs. Full table: tools.md.
customuse_delete_workflow is irreversible (assets already in My Assets survive). Never delete a workflow the user did not name.
1---2name: customuse-mcp3description: Generate and iterate on images, videos, 3D meshes, textures, rigs and Roblox-ready assets through the Customuse MCP server (node-editor workflows, CustoCoins credits). Use when: "generate an image/video", "make a 3D model of this", "turn this image into a mesh", "make a game asset / prop / character reference", "retexture this model", "rig this mesh", "decimate / UV-unwrap this mesh", "make a Roblox accessory or clothing item", "how many Customuse credits do I have", "open my Customuse workflow", "extract assets from this image", or the user names Customuse, customuse.com, CustoCoins, the nodes editor, or a model hosted there (Nano Banana, FLUX, GPT Image, Kling, Seedance, Tripo, Meshy, Hunyuan 3D, Hi3D). NOT for: local/offline image or mesh editing (use file tools, Blender, ffmpeg), inspecting an already-downloaded asset, non-Customuse generation APIs, or Unreal/engine-side import work — Customuse ends at the produced asset URL.4---56<!-- Keep this file under ~130 lines. If a section would not change what the agent does next, move it to references/. -->78# Customuse MCP910Customuse is an async, credit-based platform. Every result is a **node on a node-editor workflow** (a graph at `https://customuse.com/workflow/<id>`) the user can reopen, tweak and re-run. 16 MCP tools; the real parameter space lives in the node-type catalog, not in the tool schemas.1112## Completion contract1314Done means: the requested asset exists (`resultUrl` / `meshUrl`), it is handed to the user together with `canvasUrl`, the credit cost is stated, and anything the user asked to be saved locally is on disk. A `status: "started"` response, a created node, or an applied graph edit is **not** completion. Never end a turn while a node is still `generating`.1516## Read what this request needs1718| Need | Reference |19|---|---|20| Tool parameters, response fields, error → recovery | [tools.md](references/tools.md) |21| Which node type; exact enum, range, handle, precondition | [node-types.md](references/node-types.md) |22| Multi-node pipeline payloads, resume/repair of a broken graph | [recipes.md](references/recipes.md) |23| Writing prompts for generate vs edit vs video motion | [prompting.md](references/prompting.md) |2425Read the one that applies. Recipes are alternatives to adapt to the request, not a chain to execute end to end.2627## Preflight28291. Tools appear as `mcp__customuse__<tool>`. If missing, the server is not registered for this project directory — tell the user to run there: `claude mcp add --transport http customuse https://api.customuse.com/v1/mcp --header "Authorization: Bearer <cmk_live_…>"`. MCP scope is per project path; a worktree of a registered project does not inherit it.302. **The catalog is a mapping, not the database.** `references/node-types.md` is a dated snapshot; `customuse_list_node_types` is authoritative and account-gated. On any conflict the tool wins. If the user says a model or node type exists and your memory disagrees, call the tool unfiltered before telling them it doesn't.313. Check `customuse_get_credits_balance` before any 3D, video, cascade or autorun run.3233## Money rules3435- Balance is **not** a price. `customuse_get_credits_balance` returns what is left, never what a run costs.36- Measured `chargedCredits` 2026-09-20 — the server's "image 10–40 / 3D 55–150" wording is wrong. **Images:** `flux2Image` = 2 · `gptImage2` 1K, `flux2ProImage`, `fluxImg2Img`, the four presets = 4 · `gemini25FlashImage`/`Edit`, `fluxKontextPro`, `flux2ProEdit`, `imageOptimize` = 6 · `nanoBananaLiteImage`/`Edit`, `twoDTextures` = 7 · `gptImage2Edit` = 8 · `nanoBanana2Image`, `imageVariations` ×2 = 11 · `nanoBanana2Edit` = 16 (2K default) · `clarityUpscaler` ×2 = 17 · `gemini3ProImage`/`Edit` 1K = 20 · `assetExtractor` = 21 (on its child) · `imageToMultiview` = 27 · `bgRemoval` = 0. **3D:** mesh-post stages = 2 each · `autoRigging` = 33 · `textureGeneration` 1K = 40 · `hi3dV21Mesh3d` = 65 · `modelTextureGeneration` = 70 · `tripoV31Mesh3d` / `tripoP1Mesh3d` / `customuseCr1Mesh3d` / `meshyV7Mesh3d` / `hunyuanV31Mesh3d` / `roblox3d` = 100 · `tripoP2Mesh3d` = 130 · `hi3dV3Mesh3d` = 234. **Video:** `seedance20Video` 4 s/480p = 37 · `kling3Video` 3 s/pro = 44 (1920×1080) · `seedance25Video` 4 s/480p = 54 — price tracks duration × resolution, so "premium" Kling is the *cheaper* option at short lengths. Uploads and graph edits without a run are free; prices are versioned (`pricingVersion`) — quote them with the date.37- Exact cost per node = `customuse_get_workflow {includeData: true}` → `nodes[].data.chargedCredits` (`reimbursedCredits` after a failure). The field is per node type: present on `imageToMultiview`, **absent on `imageVariations` and its children** though the run was billed, and `customuse_duplicate_workflow` copies it verbatim — fall back to the balance delta there, and never sum across a workflow and its copy. Never report 0 for a node you did not check.38- Work stage by stage inside the scope the user approved. Ask again only before a **new kind** of charge: first video, first 3D, a cascade over several paid nodes, or an autorun budget.39- **`budgetCredits` on `customuse_autorun_workflow` is a soft cap, checked after a cycle.** Measured: budget 10 → `spentCredits: 44`, `status: "budget_exhausted"`, while the graph held one node worth 7 credits; the rest was the agent's own reasoning, billed on top. Assume a 4–5× overshoot on small budgets, quote that to the user before starting, and prefer building the graph yourself when the balance is tight.40- **Never resubmit a paid job.** A polling gap, a tool timeout or a lost response does not cancel or lose the remote run: re-poll `customuse_get_workflow` and match by node type + prompt. A second `customuse_generate` is a second charge.41- **Reuse before regenerate.** "Make a low-poly version of that" means find the existing node and run only the missing step. Lookup order: this conversation → `customuse_get_workflow` on the session workflow → `customuse_list_workflows` → ask, listing the candidates. Stop at the first confident match. Regenerating something that already exists is both a wrong answer and a second charge.4243## Core loop4445```46customuse_list_node_types # once per session, or when a type id is rejected47customuse_generate {nodeType, prompt, data} # omit workflowId on the FIRST call of the session48 → {workflowId, nodeId, runId, status:"started", canvasUrl}49customuse_get_workflow {workflowId} # poll until terminal50 → nodes[].status: idle | generating | complete | error (in flight is `generating`, not `running`)51 → resultUrl (image/video), meshUrl (3D — `resultUrl` repeats it), previewUrl (often null), error52```5354- Poll schedule: first check at ~3 s, back off ×1.5, cap at 15 s for images and 30 s for video/3D. Stop only on `complete` or `error`; anything else means still running. Measured: image ~15 s, image→mesh cascade ~2 min end to end.55- **One workflow per conversation.** Omit `workflowId` on the first generation, reuse the returned id for everything after. Pass an explicit id only to extend a workflow from `customuse_list_workflows`.56- `data` merges shallowly onto the type's `defaultData` — pass only what changes. Same for `update_nodes[].data_patch`.57- Tool results are a prose line plus a JSON blob: parse the JSON, don't read the prose. Echoed `position` is advisory — the server re-lays out nodes.58- **Check the run receipt before polling.** `customuse_run_nodes` answers `{runId, tracked_node_ids, skipped_node_ids, status}` and returns `status: "noop"` with `runId: null` — *without* `isError` — when the ids were unknown. `status: "started"` with a non-empty `tracked_node_ids` is the only green light; in `cascade` mode downstream nodes are absent from that list, so poll the graph.59- Values are validated by the provider at run time, not by the tool: an out-of-enum `data` value is accepted, stored, and comes back as a node `error` with the list of legal values (refunded). Prompts shorter than 3 characters fail the same way.60- **A node in `error` never re-runs.** `customuse_run_nodes` answers `started` but nothing executes — same `generationRunId`, same error, no charge — even after an `update_nodes` `data_patch`. Delete the node and create a corrected copy instead. Nodes that merely never ran (`idle`) do re-run normally.6162## Choosing the approach6364| Situation | Path | Never |65|---|---|---|66| One generation (text→image, edit, image→3D, video, Roblox asset) | `customuse_generate` | — |67| Chain of 2+ nodes | `customuse_edit_workflow_graph` + `run_node_ids` + `run_mode: "cascade"` | three separate `customuse_generate` calls |68| Mesh already exists, user wants texture/LOD/UV/rig | add the post-process node, connect `mesh-out → mesh-in`, run it | re-running image→3D |69| Some nodes failed mid-graph | `customuse_run_nodes` on the failed nodes + `cascade` | re-running the whole graph |70| Hands-off "just make me X", budget-capped | `customuse_autorun_workflow` → poll `customuse_get_autorun` | spending the whole balance as budget |71| User supplied a reference image | `customuse_upload_media`, then connect `image-out` | inventing a URL or a `mediaId` |7273## Building graphs7475`customuse_edit_workflow_graph` applies `create_nodes` + `connect_nodes` + `update_nodes` + `disconnect_nodes` + `delete_node_ids` in one transaction, optionally followed by a run.7677- Reference new nodes by a caller-chosen `client_id`; the response maps each to its real id. `connect_nodes` and `run_node_ids` accept either form.78- Handles are exact catalog ids: `image-out → image-in`, `mesh-out → mesh-in`, `prompt-in`, `texturePrompt-in`, `start-image-in` / `end-image-in` (video), `front|left|right|back-image-in` (multiview), `target-mesh-in` / `source-mesh-in` (bake), `mesh-1-in … mesh-10-in` (UV packing).79- Fan-out nodes spawn children when the run starts, already wired parent `image-out` → child `image-in`; the parent's own `resultUrl` is `null` or just echoes the source. Child types differ per parent: `imageVariations` → `imageVariationResult` (ids in `data.outputNodeIds`), `imageToMultiview` → `multiviewResult` (identify by `data.viewLabel`), `assetExtractor` → a single `assetExtractorPreview` (id in `data.previewNodeId`). **A `complete` parent does not mean the results are ready**: `assetExtractor` completes in ~5 s with only its analysis (`detectedParts`), while the child keeps generating for another ~45 s and carries the charge. Always poll the children, via `customuse_get_workflow {workflowId, nodeIds:["<parent>"], includeData: true}`.80- Wiring a fan-out child into a downstream node is a second, free edit call.81- Unknown types, bad handles, cycles and out-of-plan types are rejected as `invalid_request` before anything is charged — fix the shape locally rather than retrying blind.8283## Reference images8485`customuse_upload_media` takes exactly one of `url` (public http(s)), `base64` (data URI or raw + `mimeType`), or `mediaId` from `customuse_list_my_media`. It costs nothing and returns `{nodeId, imageUrl, workflowId, canvasUrl}`; the created `imageUpload` node feeds edit/3D/video nodes from `image-out` and stays `idle` with `resultUrl: null` by design. The `url` route depends on Customuse's fetcher reaching that host — measured: `upload.wikimedia.org` returns `internal_error` twice, the same bytes as `base64` succeed, so on `internal_error` switch route instead of retrying the URL. `mediaId` covers only images the user added on customuse.com: MCP uploads do **not** appear in My Media (measured), so reuse one by connecting its existing `imageUpload` node or re-passing its `imageUrl`.8687**Look at the reference before spending on it.** Download it and open it; never trust a filename, URL slug, page title or the user's description of what is in it. A file called `Toolbox.jpg` turned out to be a night shot of a house, and the variations faithfully restyled that house — 11 credits for garbage. If the image cannot be opened, say so and ask rather than wiring it into a paid node. The same applies to anything routed into a 3D node: the reference decides the result, so a wrong or cluttered reference is a wasted mesh charge.8889## Picking a node type9091Ordered defaults — when two could apply, the higher entry wins. Do not downgrade to a model because its parameters look simpler; verify the better one first.92931. Text → image: `gptImage2` (4 credits, cleanest subject separation and text) or `flux2ProImage` (4) for drafts and layouts; `nanoBanana2Image` (11) when photo-realism matters most; `gemini3ProImage` for maximum fidelity; `nanoBananaLiteImage` (7) only when an even cheaper draft is wanted.942. Game-asset concept art with a free alpha background: `gameAsset` / `vehicle` / `character` / `clothingReference` (4 each). They **rewrite the prompt** into a "3D stylized game X, 3/4 front angle, transparent background" template, so camera and background wording is ignored — pick a plain model instead when those matter.953. Edit an existing image (needs `image-in`): `nanoBanana2Edit`; `gptImage2Edit` for text/typography; `fluxKontextPro` for style transfer. Several takes of one image: `imageVariations`.964. Prepare an image for 3D: `imageOptimize` (6; white bg, centered, A/T-pose). It is a **pass-through**: it completes with `resultUrl: null` and hands the corrected image to whatever pulls its `image-out`, so there is nothing to show the user from it. Then `bgRemoval` (free) or `clarityUpscaler` (17, 1024→2048) only if still needed. Back-side accuracy: `imageToMultiview` (27) before a multiview mesher.975. Image → **textured** mesh in one node: `modelTextureGeneration` (Customuse CR1) — 70 credits, ~3.5 min, PBR maps in `textureMaps` (albedo/normal/orm). Cheaper and simpler than `tripoV31Mesh3d` + `textureGeneration` (100 + 40).986. Image → geometry only (all untextured, measured at `faceLimit: 12000`): `meshyV7Mesh3d` (100) or `tripoP2Mesh3d` (130) keep stamped relief on hard-surface props · `tripoV31Mesh3d` / `tripoP1Mesh3d` / `customuseCr1Mesh3d` (100) are smoother and flatten fine detail · `hunyuanV31Mesh3d` (100) gives the cleanest surface at an exact 40 000 tris · `hi3dV21Mesh3d` (65) is cheapest but ignores the budget (676 k tris) and `hi3dV3Mesh3d` (234) is the density option. **Hi3D requires `faceLimit` ≥ 100 000**; Hi3D and Hunyuan ship POSITION only, so add `meshCleanup` (`recalculateNormals`) + `uvUnwrap` before texturing. `quad: true` never survives the GLB export.997. Mesh post (2 credits each unless noted): `meshCleanup`, `meshDecimation` (LOD), `uvUnwrap`, `uvPacking`, `textureBaking` (`bakeChannel` is an **array**: `all|base-color|normal|roughness|specular|metalness`), `textureGeneration` (retexture, 40), `autoRigging` (33 — the provider accepts only `aquatic|avian|biped|hexapod|octopod|quadruped|serpentine`). Tileable PBR maps from a photo: `twoDTextures` (7) returns `baseColorUrl` / `normalUrl` / `roughnessUrl` / `metalnessUrl`.1008. Roblox deliverable: `roblox3d` with the matching `generationType` (100, ~5 min, comes out textured) — not a generic mesh node.1019. Video (all three verified): `seedance20Video` (4–15 s, `480p|720p|1080p|4k`) = 37 for 4 s @480p · `kling3Video` (3–15 s, `pro|4k`) = 44 for 3 s @pro and delivers full 1920×1080 · `seedance25Video` (4–30 s, `mov` option) = 54 for 4 s @480p. Match `videoInputMode` to the wiring and set `generateAudio: false` unless sound is wanted — it defaults to **true** on both Seedance nodes. Video nodes expose a poster frame in `data.mediaArtifacts.posterUrl` / `thumbnailUrl`, so a still can be shown without downloading the clip.10210. Break one object into parts: `assetExtractor` (21) — see the fan-out note below; it decomposes a single subject, it does not split a multi-object image.10311. Character/NPC model end to end: `character` → `imageOptimize` (`aPose`) → `modelTextureGeneration` → `autoRigging` `biped`. Measured 113 credits, ~6.5 min, 18 986 tris, 58 joints. The **rigged GLB loses the textures** — hand over the textured mesh and the rigged file together. See [recipes.md](references/recipes.md) recipe 12.104105## Delivery106107- Hand over: the asset URL, `canvasUrl`, the workflow id and node ids (they make the next request cheap), the credit cost, and one concrete limitation.108- Save locally only what the user asked for, or when they are clearly working in a repo: `./customuse/<workflow-slug>/<nodeType>-<first8-of-nodeId>.<ext>`. Never overwrite an existing file; verify the download is non-empty and of the expected type.109- Open results before describing them. Images: open `resultUrl`. 3D: the top-level `previewUrl` is usually `null`, but `customuse_get_workflow {includeData: true}` exposes `data.thumbnailUrl` — a real render (verified) — so open that; check `textureMaps` / `isPBR` for texture presence, and parse the GLB (magic `glTF`, triangle/vertex counts) only for numbers a render cannot show. A render establishes subject, composition and completeness, never topology, watertightness, UV or rig quality. Never imply you inspected something you did not open.110- Keep chat clean: polling is silent (a status change is worth a line, individual polls are not), no raw node/run ids, no tool names, no JSON dumps unless the user asks.111112## Errors113114`isError: true` responses carry `structuredContent.error.code`: `invalid_request` (bad node type, non-existent handle — the message lists the valid ones, graph cycle, two upload sources), `not_found` (well-formed but unknown workflow or autorun session), `not_enough_credits` (stop, tell the user to top up at customuse.com — never retry in a loop), `internal_error` (server-side; for an upload switch route, otherwise one retry then report). Nothing is charged for any of them. Malformed arguments fail earlier still, as `MCP error -32602: Input validation error` with no code. A node ending `status: "error"` is not a tool error: it is refunded automatically (`reimbursedCredits`); read `nodes[].error` — provider messages name the offending field — before retrying with different inputs. Full table: [tools.md](references/tools.md).115116`customuse_delete_workflow` is irreversible (assets already in My Assets survive). Never delete a workflow the user did not name.