Skip to content
MCPBytes
DocsSplit a 3D model into parts

Tool reference · 3D Models

Split a 3D model into parts

Split a 3D model into separate part meshes, with colliders and physics metadata.

MCP tool
split_3d_model
MCP endpoint
/mcp/3d
REST
POST /v1/tools/split_3d_model/jobs
Price
From 20 credits

Overview

Send a 3D model and MCPBytes splits it into separate part meshes. Every part gets a convex collider, and manifest.json describes how the parts fit together: bounds, contacts, symmetry, and mass estimates.

Input formats
.glb .gltf .obj .ply .stl .off .blend
Part formats
GLB (default), OBJ or PLY
Detail
low, medium (default) or high
Outputs
Part meshes, convex colliders, segmented.glb, manifest.json, face_to_part.bin, and all of them as one .zip
Metadata
Bounds, contacts, symmetry, mass and inertia estimates

Quickstart

Send the file as the request body with the options in the query string, or refer to it in a JSON body (upload_id or url) with an options object. The response is the new job; poll it until its status is final, then download the files in result.files.

# The model file is the request body
curl "https://api.mcpbytes.com/v1/tools/split_3d_model/jobs?filename=airplane.glb" \
  -H "Authorization: Bearer $MCPBYTES_API_KEY" \
  --data-binary @airplane.glb
Response202 Accepted
{
  "id": "j_4f7k2m9x1q8w3e6r5t0y2u7i9o",
  "tool": "split_3d_model",
  "status": "queued",
  "input": {
    "name": "airplane.glb",
    "bytes": 2481152,
    "source": "body"
  },
  "options": {
    "detail": "medium",
    "min_part_faces": 0,
    "min_part_area": null,
    "format": "glb",
    "preprocess": "auto",
    "segmented": true,
    "density": null,
    "max_parts": 32
  },
  "error": null,
  "result": null,
  "compute_ms": null,
  "credits_charged": null,
  "created_at": "2026-09-19T12:00:00.000Z",
  "started_at": null,
  "finished_at": null,
  "outputs_expire_at": "2026-09-20T12:00:00.000Z"
}
Get the resultjob.sh
# JOB_ID is the id from the create response
curl https://api.mcpbytes.com/v1/jobs/$JOB_ID \
  -H "Authorization: Bearer $MCPBYTES_API_KEY"
Response200 OK · trimmed
{
  "id": "j_4f7k2m9x1q8w3e6r5t0y2u7i9o",
  "tool": "split_3d_model",
  "status": "succeeded",
  "result": {
    "files": [
      {
        "name": "airplane_parts.zip",
        "bytes": 1873410,
        "sha256": "",
        "url": "https://api.mcpbytes.com/blob/dl/j_4f7k2m9x1q8w3e6r5t0y2u7i9o/airplane_parts.zip?t=…"
      },
      {
        "name": "collision/part_000.glb",
        "bytes": 4212,
        "sha256": "",
        "url": "https://api.mcpbytes.com/blob/dl/j_4f7k2m9x1q8w3e6r5t0y2u7i9o/collision/part_000.glb?t=…"
      },
      {
        "name": "manifest.json",
        "bytes": 20931,
        "sha256": "",
        "url": "https://api.mcpbytes.com/blob/dl/j_4f7k2m9x1q8w3e6r5t0y2u7i9o/manifest.json?t=…"
      },
      {
        "name": "meshes/part_000.glb",
        "bytes": 512604,
        "sha256": "",
        "url": "https://api.mcpbytes.com/blob/dl/j_4f7k2m9x1q8w3e6r5t0y2u7i9o/meshes/part_000.glb?t=…"
      }
    ],
    "schema_version": 2,
    "part_count": 7,
    "input_faces": 48210,
    "exported_faces": 48210,
    "notes": [],
    "timings_s": {
      "total": 12.4
    }
  },
  "compute_ms": 14210,
  "credits_charged": 20,
  "finished_at": "2026-09-19T12:00:16.000Z",
  "outputs_expire_at": "2026-09-20T12:00:00.000Z"
}

A job can be canceled while it is queued: POST /v1/jobs/{id}/cancel.

More on statuses, downloads and retention in Jobs & files.

Input

One file per job, in one of these ways. The formats it accepts are listed in the overview.

Input sources
File body
REST only: the file itself as the request body, with ?filename= and the options in the query string.
upload_id
Create an upload URL (POST /v1/uploads, or create_upload over MCP), PUT the file to it, then pass the upload_id. Upload URLs expire after an hour.
url, filename
A public https URL. Add filename when the URL does not end in the file's extension.
# 1. Create an upload URL (valid for one hour)
curl https://api.mcpbytes.com/v1/uploads \
  -H "Authorization: Bearer $MCPBYTES_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"filename": "airplane.glb"}'

# 2. PUT the file to the "url" from the response
curl -X PUT --data-binary @airplane.glb "$UPLOAD_URL"

# 3. Start the job with the "upload_id"
curl https://api.mcpbytes.com/v1/tools/split_3d_model/jobs \
  -H "Authorization: Bearer $MCPBYTES_API_KEY" \
  -H "Content-Type: application/json" \
  -d "{
    \"upload_id\": \"$UPLOAD_ID\",
    \"options\": {
      \"detail\": \"high\"
    }
  }"

To retry safely, send an Idempotency-Key header (or idempotency_key in a JSON body): a repeated key returns the original job instead of starting a new one.

Options

Put options in the query string when the file is the request body, in the options object of a JSON body, or pass them as arguments of the MCP tool. Leave an option out to use its default.

Options
detail
low | medium | highHow finely to split: low = major assemblies, high = sub-parts. Default medium.
format
glb | obj | plyPart file format. Default glb.
max_parts
1–64Safety ceiling on the part count, which is chosen automatically. Capped by the plan: 32 on free, 64 on pro.
min_part_faces
integerMerge parts with fewer faces. Default 0.
min_part_area
0 ≤ value < 1, or nullMerge parts below this fraction of the surface area. Default depends on detail.
preprocess
auto | on | offConnectivity cleanup of the working mesh. Default auto.
segmented
true | falseAlso write segmented.glb, all parts color-coded. Default true.
density
numberMass per cubic model unit, for mass estimates. Default 100.

Outputs

A succeeded job lists its files in result.files, each with a download url.

Output files
manifest.json
Every part: file, bounds, contacts, symmetry, collider, mass and inertia estimates.
segmented.glb
All parts in one file, color-coded, for a quick visual check.
meshes/part_NNN.glb
Each part's original geometry, materials and textures.
collision/part_NNN.glb
A convex collider per part, in the same coordinates.
metadata/face_to_part.bin
The part id of every original triangle, for hit tests on the intact model.
<model>_parts.zip
All of the above in one archive, for a single download (left out, with a note, above 100 MB).

Parts are numbered by decreasing surface area, so part_000 is the largest. With format set to obj or ply, meshes and colliders use that extension. All files share one coordinate system: place every part and collider at the model's root transform to rebuild it.

Result summary

Next to files, the job's result has a summary you can check without downloading anything:

result
part_count
Parts written.
input_faces
Triangles in the input.
exported_faces
Triangles written to parts. Equal to input_faces unless faces had non-finite coordinates (listed in notes).
schema_version
Version of the manifest.json format.
notes
Warnings, for example an archive left out above 100 MB.
timings_s
Processing time in seconds (total).

Tips

  • Start with the defaults. If the parts are too coarse, run again with detail high; if there are too many small parts, use detail low or raise min_part_area. Each run is charged again.
  • Read manifest.json first. Part names carry no meaning, so find the part you need by its bounds and contacts.
  • Download <model>_parts.zip for everything at once, or single files from result.files when only some parts are needed.
  • Blender input is converted to glTF axes (+Y up, +Z forward); source_to_output_transform in manifest.json relates the parts to the original scene. Formats without known axes or units report those fields as null.
  • A model over the face limit fails with limit_exceeded: reduce it with simplify_3d_model first.

MCP

Your agent calls split_3d_model. Connect it to https://api.mcpbytes.com/mcp/3d for this tool and the rest of its family (Create a 3D model, Create a 3D model from an image, Optimize a 3D model, Simplify a 3D model, Inspect a 3D model), or to https://api.mcpbytes.com/mcp for every tool.

Claude Code

The first form signs in through the browser when you run /mcp. In .mcp.json (project root), ${MCPBYTES_API_KEY} is read from the environment when Claude Code connects. Claude Code docs

claude mcp add --transport http mcpbytes \
  https://api.mcpbytes.com/mcp/3d
Codex (CLI, IDE extension, ChatGPT desktop)

Codex reads the key from the environment variable each time it connects. The same table can go in ~/.codex/config.toml by hand; codex mcp add has no --header flag. Codex docs

codex mcp add mcpbytes --url https://api.mcpbytes.com/mcp/3d \
  --bearer-token-env-var MCPBYTES_API_KEY
Cursor

~/.cursor/mcp.json (all projects) or .cursor/mcp.json (one project). Remote servers take no "type". Without the header, the client signs you in with GitHub or an email link (OAuth). Cursor docs

~/.cursor/mcp.json
{
  "mcpServers": {
    "mcpbytes": {
      "url": "https://api.mcpbytes.com/mcp/3d",
      "headers": {
        "Authorization": "Bearer ${env:MCPBYTES_API_KEY}"
      }
    }
  }
}
11 more clients in the docs →

Arguments

The tool's options are flat arguments. Besides them:

split_3d_model arguments
upload_id
From create_upload, after the agent has PUT the file.
url, filename
A public https URL, and the file name when the URL does not end in the extension.
wait_seconds
0–45, default 30How long the call waits for the result. If the job is still running, the agent calls get_job.
idempotency_key
OptionalReuse it with the same arguments when retrying after a network error.

What the agent sees

MCP tools
split_3d_model
Starts a job that splits a 3D model into separate part meshes, each with a convex collider, plus manifest.json (bounds, contacts, symmetry, mass estimates). Give upload_id (from create_upload) or a public https url. Waits up to wait_seconds for the result. Costs 20 credits up to 50,000 faces, 50 credits up to 200,000 faces.
create_upload
Returns a one-hour URL to PUT a local file to; then call the tool with the upload_id.
get_job
Status and results of a job; waits up to wait_seconds for it to finish.
cancel_job
Cancel a queued job or a workflow whose can_cancel is true; repeated calls never delete results.
list_jobs
Your most recent jobs, newest first.
read_job_file
Reads a text output (.txt .json .md .csv) of a succeeded job in chunks.

Setup for every client, and how agents upload files and read results: Connect over MCP.

Agent skill

The MCPBytes skill teaches agents this tool, in references/split_3d_model.md. Agents without MCP run it through the REST API with the skill's script, which reads your key from MCPBYTES_API_KEY:

mcpbytes.py
python scripts/mcpbytes.py run split_3d_model chair.glb --out parts/
python scripts/mcpbytes.py run split_3d_model chair.glb \
  -o detail=high --out parts/
python scripts/mcpbytes.py read j_... manifest.json

Pricing

From 20 credits. The price follows the input's size and is charged once the input has been measured; starting a job needs at least the smallest price. A job that fails costs nothing: its charge is refunded.

Up to 50,000 faces
20 credits
Up to 200,000 faces
50 credits

One credit balance pays for every tool, and a new account starts with free credits. See Credits & prices or buy credits.

Limits

Limits
Model size
Up to 200,000 faces
At a time
1 job
Uploads
Up to 50 MB
Results
24 hours by default

GET /v1/me returns your limits and current usage; Limits & errors explains what happens when one is reached.

Errors

A failed job comes back with error.code, error.message and often error.hint. Codes are stable. Inputs that fail with a validation error will fail again unchanged.

Job errors
invalid_mesh
The file is corrupt or has no usable triangle geometry.
unsupported_feature
A valid file uses an unsupported feature, such as Draco compression.
limit_exceeded
The model has more faces than your plan allows.
segmentation_failed
No usable parts were found.
unsupported_format
The tool does not take this file type.
insufficient_credits
The job costs more than the balance, which is known once the input has been measured. Nothing was charged.
timeout
The job did not finish within its time limit.
out_of_memory
The file needs more memory than a job has.

Requests can also fail before a job starts, with an HTTP status: see HTTP errors.