AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified MIT Self-run

Meshy 3d Generation

skill-meshy-dev-meshy-3d-agent-meshy-3d-generation · by meshy-dev

Generate 3D models, textures, images, rig characters, and animate them using the Meshy AI API. Handles API key detection, setup, and all generation workflows via direct HTTP calls. Use when the user asks to create 3D models, convert text/images to 3D, texture models, rig or animate characters, or interact with the Meshy API.

No reviews yet
0 installs
16 views
0.0% view→install

Install

$ agentstack add skill-meshy-dev-meshy-3d-agent-meshy-3d-generation

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access Used
  • Filesystem access Used
  • Shell / process execution No
  • Environment & secrets Used
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-meshy-dev-meshy-3d-agent-meshy-3d-generation)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
1mo ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Meshy 3d Generation? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

Meshy 3D Generation

Directly communicate with the Meshy AI API to generate 3D assets. This skill handles the complete lifecycle: environment setup, API key detection, task creation, polling, downloading, and chaining multi-step pipelines.

For full endpoint reference (all parameters, response schemas, error codes), read [reference.md](reference.md).


IMPORTANT: 3D Printing → Use meshy-3d-printing Skill

If the user's request involves 3D printing (keywords: print, 3d print, slicer, slice, bambu, orca, prusa, cura, multicolor, 3mf, figurine, miniature, statue, physical model), use the meshy-3d-printing skill instead of this one for the entire workflow. The printing skill handles generation with correct print-optimized parameters (e.g. target_formats with "3mf" for multicolor), slicer detection, coordinate conversion, and slicer launch — all in one pipeline.

This skill's create_task/poll_task/download template functions are reused by the printing skill, but the workflow orchestration (what to generate, which formats, what to do after) must come from the printing skill when printing is involved.

Do NOT generate a model with this skill and then hand off to the printing skill — the printing skill needs to control parameters from the start (e.g. target_formats, should_texture).


IMPORTANT: First-Use Session Notice

When this skill is first activated in a session, inform the user:

> All generated files will be saved to meshy_output/ in the current working directory. Each project gets its own folder ({YYYYMMDD_HHmmss}_{prompt}_{id}/) with model files, textures, thumbnails, and metadata. History is tracked in meshy_output/history.json.

This only needs to be said once per session, at the beginning.

IMPORTANT: File Organization

All downloaded files MUST go into a structured meshy_output/ directory in the current working directory. Do NOT scatter files randomly.

  • Each project gets its own folder: meshy_output/{YYYYMMDD_HHmmss}_{prompt_slug}_{task_id_prefix}/
  • For chained tasks (preview → refine → rig), reuse the same project_dir
  • Track tasks in metadata.json per project, and global history.json
  • Auto-download thumbnails alongside models

The Reusable Script Template below includes get_project_dir(), record_task(), and save_thumbnail() helpers.


IMPORTANT: Shell Command Rules

Use only standard POSIX tools in shell commands. Do NOT use rg (ripgrep), fd, or other non-standard CLI tools — they may not be installed. Use these standard alternatives instead:

| Do NOT use | Use instead | |---|---| | rg | grep | | fd | find | | bat | cat | | exa / eza | ls |


IMPORTANT: Run Long Tasks Properly

Meshy generation tasks take 1–5 minutes. When running Python scripts that poll for completion:

  • Write the entire create → poll → download flow as ONE Python script and execute it in a single Bash call. Do NOT split into multiple commands. This keeps the API key, task IDs, and session in one process context.
  • Use python3 -u script.py (unbuffered) so progress output is visible in real time.
  • Be patient with long-running scripts — do NOT interrupt or kill them prematurely. Tasks at 99% for 30–120s is normal finalization, not a failure.

Step 0: Environment Detection (ALWAYS RUN FIRST)

Before any API call, detect whether the environment is ready:

echo "=== Meshy API Key Detection ==="

# 1. Check current env var
if [ -n "$MESHY_API_KEY" ]; then
  echo "ENV_VAR: FOUND (${MESHY_API_KEY:0:8}...)"
else
  echo "ENV_VAR: NOT_FOUND"
fi

# 2. Check .env files in workspace
for f in .env .env.local; do
  if [ -f "$f" ] && grep -q "MESHY_API_KEY" "$f" 2>/dev/null; then
    echo "DOTENV($f): FOUND"
    export $(grep "MESHY_API_KEY" "$f" | head -1)
  fi
done

# 3. Check shell profiles
for f in ~/.zshrc ~/.bashrc ~/.bash_profile ~/.profile; do
  if [ -f "$f" ] && grep -q "MESHY_API_KEY" "$f" 2>/dev/null; then
    echo "SHELL_PROFILE: FOUND in $f"
  fi
done

# 4. Final status
if [ -n "$MESHY_API_KEY" ]; then
  echo "READY: key=${MESHY_API_KEY:0:12}..."
else
  echo "READY: NO_KEY_FOUND"
fi

# 5. Python requests check
python3 -c "import requests; print('PYTHON_REQUESTS: OK')" 2>/dev/null || echo "PYTHON_REQUESTS: MISSING (run: pip install requests)"

echo "=== Detection Complete ==="

Decision After Detection

  • Key found → Proceed to Step 1.
  • Key NOT found → Go to Step 0a.
  • Python requests missing → Run pip install requests.

Step 0a: API Key Setup (Only If No Key Found)

Tell the user:

> To use the Meshy API, you need an API key. Here's how to get one: > > 1. Go to https://www.meshy.ai/settings/api > 2. Click "Create API Key", give it a name, and copy the key (it starts with msy_) > 3. The key is only shown once — save it somewhere safe > > Note: API access requires a Pro plan or above. Free-tier accounts cannot create API keys. If you see "Please upgrade to a premium plan to create API tasks", you'll need to upgrade at https://www.meshy.ai/pricing first.

Once the user provides their key, set it and verify:

macOS (zsh):

export MESHY_API_KEY="msy_PASTE_KEY_HERE"

# Verify
STATUS=$(curl -s -o /dev/null -w "%{http_code}" \
  -H "Authorization: Bearer $MESHY_API_KEY" \
  https://api.meshy.ai/openapi/v1/balance)

if [ "$STATUS" = "200" ]; then
  BALANCE=$(curl -s -H "Authorization: Bearer $MESHY_API_KEY" https://api.meshy.ai/openapi/v1/balance)
  echo "Key valid. $BALANCE"
  echo 'export MESHY_API_KEY="msy_PASTE_KEY_HERE"' >> ~/.zshrc
  echo "Persisted to ~/.zshrc"
else
  echo "Key invalid (HTTP $STATUS). Check the key and try again."
fi

Linux (bash):

export MESHY_API_KEY="msy_PASTE_KEY_HERE"

# Verify (same as above), then persist to ~/.bashrc
STATUS=$(curl -s -o /dev/null -w "%{http_code}" \
  -H "Authorization: Bearer $MESHY_API_KEY" \
  https://api.meshy.ai/openapi/v1/balance)

if [ "$STATUS" = "200" ]; then
  BALANCE=$(curl -s -H "Authorization: Bearer $MESHY_API_KEY" https://api.meshy.ai/openapi/v1/balance)
  echo "Key valid. $BALANCE"
  echo 'export MESHY_API_KEY="msy_PASTE_KEY_HERE"' >> ~/.bashrc
  echo "Persisted to ~/.bashrc"
else
  echo "Key invalid (HTTP $STATUS). Check the key and try again."
fi

Windows (PowerShell):

$env:MESHY_API_KEY = "msy_PASTE_KEY_HERE"

# Verify
$status = (Invoke-WebRequest -Uri "https://api.meshy.ai/openapi/v1/balance" -Headers @{Authorization="Bearer $env:MESHY_API_KEY"} -UseBasicParsing).StatusCode
if ($status -eq 200) {
    Write-Host "Key valid."
    # Persist permanently
    [System.Environment]::SetEnvironmentVariable("MESHY_API_KEY", $env:MESHY_API_KEY, "User")
    Write-Host "Persisted to user environment variables. Restart terminal to take effect."
} else {
    Write-Host "Key invalid (HTTP $status). Check the key and try again."
}

Alternative (all platforms): Create a .env file in your project root:

MESHY_API_KEY=msy_PASTE_KEY_HERE

Step 1: Confirm Plan With User Before Spending Credits

CRITICAL: Before creating any task, present the user with a summary and get confirmation:

I'll generate a 3D model of "" using the following plan:

  1. Preview (mesh generation) — 5-20 credits (meshy-6/lowpoly: 20, others: 5)
  2. Refine (texturing with PBR) — 10 credits
  3. Download as .glb

  Total cost: 30 credits
  Current balance:  credits

  Shall I proceed?

For multi-step pipelines (e.g., text-to-3d → rig → animate), present the FULL pipeline cost upfront:

| Step | API | Credits | |---|---|---| | Preview | Text to 3D | 20 | | Refine | Text to 3D | 10 | | Rig | Auto-Rigging | 5 | | Total | | 35 |

> Note: Rigging automatically includes basic walking + running animations for free (in result.basic_animations). Only add Animate (3 credits) if the user needs a custom animation beyond walking/running.

Wait for user confirmation before executing.

Intent → API Mapping

| User wants to... | API | Endpoint | Credits | |---|---|---|---| | 3D model from text | Text to 3D | POST /openapi/v2/text-to-3d | 5–20 (preview) + 10 (refine) | | 3D model from one image | Image to 3D | POST /openapi/v1/image-to-3d | 5–30 | | 3D model from multiple images | Multi-Image to 3D | POST /openapi/v1/multi-image-to-3d | 5–30 | | New textures on existing model | Retexture | POST /openapi/v1/retexture | 10 | | Change mesh format/topology | Remesh | POST /openapi/v1/remesh | 5 | | Convert a model to other formats (no remesh) | Convert | POST /openapi/v1/convert | 1 | | Rescale a model to real-world size | Resize | POST /openapi/v1/resize | 1 | | Generate fresh UVs (GLB, ≤40k faces) before external texturing | UV Unwrap | POST /openapi/v1/uv-unwrap | 5 | | Add skeleton to character | Auto-Rigging | POST /openapi/v1/rigging | 5 (includes walking + running) | | Animate a rigged character (custom) | Animation | POST /openapi/v1/animations | 3 | | 2D image from text (recommended pre-step before image-to-3d) | Text to Image | POST /openapi/v1/text-to-image | 3 / 6 / 9 / 9 | | Optimize/edit a 2D image (recommended pre-step before image-to-3d) | Image to Image | POST /openapi/v1/image-to-image | 3 / 6 / 9 / 12 | | Check FDM printability (watertight / non-manifold edges / holes) | Analyze Printability | POST /openapi/v1/print/analyze | 0 (free) | | Repair non-manifold/degenerate-face/hole topology | Repair Printability | POST /openapi/v1/print/repair | 10 | | Multi-color 3D print | Multi-Color Print | POST /openapi/v1/print/multi-color | 10 | | Stylized printable product from a photo (figure / lamp / keychain / fridge-magnet) | Creative Lab — see the meshy-3d-printing skill for the full prototype→build flow | POST /openapi/creative-lab/{product}/v1/{prototype,build} | 36 (6+30) | | Check credit balance | Balance | GET /openapi/v1/balance | 0 |


Step 2: Execute the Workflow

CRITICAL: Async Task Model

All generation endpoints return {"result": ""}, NOT the model. You MUST poll.

NEVER read model_urls from the POST response.

Reusable Script Template

Use this as the base for ALL generation workflows:

#!/usr/bin/env python3
"""Meshy API task runner. Handles create → poll → download."""
import requests, time, os, sys

API_KEY = os.environ.get("MESHY_API_KEY", "")
if not API_KEY:
    sys.exit("ERROR: MESHY_API_KEY not set")

BASE = "https://api.meshy.ai"
HEADERS = {"Authorization": f"Bearer {API_KEY}"}
SESSION = requests.Session()
SESSION.trust_env = False  # bypass any system proxy settings

def create_task(endpoint, payload):
    resp = SESSION.post(f"{BASE}{endpoint}", headers=HEADERS, json=payload, timeout=30)
    if resp.status_code == 401:
        sys.exit("ERROR: Invalid API key (401)")
    if resp.status_code == 402:
        try:
            bal = SESSION.get(f"{BASE}/openapi/v1/balance", headers=HEADERS, timeout=10)
            balance = bal.json().get("balance", "unknown")
            sys.exit(f"ERROR: Insufficient credits (402). Current balance: {balance}. Top up at https://www.meshy.ai/pricing")
        except Exception:
            sys.exit("ERROR: Insufficient credits (402). Check balance at https://www.meshy.ai/pricing")
    if resp.status_code == 429:
        sys.exit("ERROR: Rate limited (429). Wait and retry.")
    resp.raise_for_status()
    task_id = resp.json()["result"]
    print(f"TASK_CREATED: {task_id}")
    return task_id

def poll_task(endpoint, task_id, timeout=300):
    """Poll task with exponential backoff (5s→30s, fixed 15s at 95%+)."""
    elapsed = 0
    delay = 5            # Initial delay: 5s
    max_delay = 30       # Cap: 30s
    backoff = 1.5        # Backoff multiplier
    finalize_delay = 15  # Fixed delay during finalization (95%+)
    poll_count = 0
    while elapsed = 95 else delay
        time.sleep(current_delay)
        elapsed += current_delay
        if progress  **Refine compatibility**: Refine works with `meshy-5`, `meshy-6`, or `latest` (= Meshy 6) — pick the same family as your preview for consistency. Refine costs 10 credits regardless of model. (`meshy-4` is retired and returns 400.)

### (Optional but strongly recommended) 2D Optimization Pre-Step

**Prefer the image-to-3d route over direct text-to-3d** — it's higher quality and more controllable, so for a text-only request make a design image first, then 3D-ify.

Image quality directly determines 3D model quality. Before calling `/openapi/v1/image-to-3d` or `/openapi/v1/multi-image-to-3d`, evaluate the user's input and proactively suggest a 2D pass:

| User input | Recommended pre-step |
|---|---|
| Only a text description, no reference image | `/openapi/v1/text-to-image` with `nano-banana-pro`. For characters add `generate_multi_view: True` and `pose_mode: "a-pose"` or `"t-pose"` for rig-friendly output. |
| Reference image is low-resolution / cluttered background / unclear subject / bad lighting | `/openapi/v1/image-to-image` with `nano-banana-pro` to clean up (remove background, raise resolution, normalize lighting, fill occlusions). |
| User wants to adjust style / colors / details | `/openapi/v1/image-to-image` for style transfer, then 3D-ify. |

The optimized image URL feeds directly into `/openapi/v1/image-to-3d`'s `image_url`. **3-9 extra credits typically buy a noticeable quality bump**, and downstream `refine` / texture-on-mesh stages benefit too.

**Skip when**: the user already provided a clean front-facing studio shot — go straight to image-to-3d. Also skip for **Creative Lab** products (figure / lamp / keychain / fridge-magnet): they apply their own built-in stylization, so feed the raw photo (or text, for lamp) straight to Creative Lab — do not pre-generate a design image.

```python
# Example: text-only request → text-to-image → image-to-3d
img_id = create_task("/openapi/v1/text-to-image", {
    "ai_model": "nano-banana-pro",
    "prompt": "studio render of a sci-fi helmet, neutral background, even lighting",
    "aspect_ratio": "1:1",
    # "generate_multi_view": True,   # for character meshes use multi-view + pose_mode
})
img_task = poll_task("/openapi/v1/text-to-image", img_id)
generated_image_url = img_task["image_urls"][0]   # use as input for image-to-3d below

Image to 3D

import base64

# For local files, convert to data URI:
# with open("photo.jpg", "rb") as f:
#     image_url = "data:image/jpeg;base64," + base64.b64encode(f.read()).decode()

task_id = create_task("/openapi/v1/image-to-3d", {
    "image_url": "IMAGE_URL_OR_DATA_URI",
    "should_texture": True,
    "enable_pbr": True,            # Default is False; set True for metallic/roughness/normal maps
    "ai_model": "latest",
    # "image_enhancement": True,   # Optimize input image (meshy-6/latest only, default True)
    # "remove_lighting": True,     # Remove baked lighting from texture (meshy-6/latest only, default True)
})

task = poll_task("/openapi/v1/image-to-3d", task_id)
download(task["model_urls"]["glb"], "model.glb")

Multi-Image to 3D

task_id = create_task("/openapi/v1/multi-image-to-3d", {
    "image_urls": ["URL_1", "URL_2", "URL_3"],  # 1–4 images
    "should_texture": True,
    "enable_pbr": True,            # Default is False; set True for metallic/roughness/normal maps
    "ai_model": "latest",
    # "image_enhancement": True,   # Optimize input images (meshy-6/latest only, default True)
    # "remove_lighting": True,     # Remove baked lighting from texture (meshy-6/latest only, default True)
})
task = poll_task("/openapi/v1/multi-image-to-3d", task_id)
download(task["model_urls"]["glb"], "model.glb")

Retexture

IMPORTANT: Before calling, ask the user to provide a texture style:

  • Text prompt: e.g. "rusty metal", "cartoon style" → text_style_prompt
  • Reference image: URL of style image → image_style_url

One of these is required. If both provided, image_style_url takes precedenc

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.