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{
"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"
}# JOB_ID is the id from the create response
curl https://api.mcpbytes.com/v1/jobs/$JOB_ID \
-H "Authorization: Bearer $MCPBYTES_API_KEY"{
"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.
- 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.
- 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.
- 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:
- 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 CodeOAuth or API key
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/3dCodex (CLI, IDE extension, ChatGPT desktop)OAuth or API key
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_KEYCursorOAuth or API key
~/.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
{
"mcpServers": {
"mcpbytes": {
"url": "https://api.mcpbytes.com/mcp/3d",
"headers": {
"Authorization": "Bearer ${env:MCPBYTES_API_KEY}"
}
}
}
}Arguments
The tool's options are flat arguments. Besides them:
- 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
- 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:
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.jsonPricing
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
- 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.
- 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.