BumpMesh MCP
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@BumpMesh MCPApply height-map.png to housing.stl with triplanar projection and 0.3 mm amplitude."
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
BumpMesh MCP
A local MCP server that applies real image-driven displacement to STL/OBJ meshes using CNC Kitchen's BumpMesh/stlTexturizer. No browser, WebGL, LLM calls, or runtime network downloads are involved.
The TypeScript adapter runs the upstream JavaScript computational core directly. Python or Rust would require a JavaScript subprocess or an algorithm port without a demonstrated benefit for this workload. Node keeps a single runtime and the original mesh algorithms. A worker thread keeps mesh processing off the MCP event loop; this is isolation and cancellation support, not a claim of faster geometry processing.
Install and run
Requires Node.js 22+ and npm. Development was tested on macOS Apple Silicon. sharp uses a native image decoder with platform-specific prebuilt packages; a supported Node/platform combination is required.
git clone https://github.com/kolengri/bumpmesh-mcp.git
cd bumpmesh-mcp
npm ci
npm run build
mkdir -p files
node dist/index.js --root "$PWD/files"The default transport is stdio. Waiting silently for MCP messages is expected. Diagnostics go to stderr; stdout is reserved for MCP.
npm test
npm run verify:vendor
npm run demoThe demo creates a synthetic cube, a grayscale texture, textured STL and 3MF, and a JSON report under a new demo-output/<timestamp> directory. It exercises the real stdio MCP protocol. No personal files are read or uploaded.
Related MCP server: obrobka-mcp
Tools
Tool | Purpose |
| Formats, limits, units, upstream version, and configured file root |
| Triangle count, bounds, degenerate triangles, open/non-manifold edge counts |
| Load, subdivide, displace, optionally decimate/repair, export, and return diagnostics |
Inputs: ASCII/binary STL and OBJ geometry. OBJ meshes are merged; materials, UVs, lines, and points are ignored. Textures: single-frame PNG, JPEG, WebP. Exports: binary STL and single-mesh 3MF in millimeters. STEP and 3MF import are deliberately outside this initial adapter, even though the browser application supports them.
Example apply_texture arguments (paths are relative to the configured root):
{
"model_path": "housing.stl",
"texture_path": "height-map.png",
"output_path": "housing-textured.stl",
"projection": "triplanar",
"amplitude_mm": 0.3,
"tile_size_mm": 5,
"refine_length_mm": 0.4,
"max_triangles": 100000,
"exclude_bottom_deg": 5,
"exclude_top_deg": 5
}Parameter semantics
Coordinates are interpreted as millimeters, with Z up. No scaling, recentering, orientation conversion, or automatic repair of the input is performed.
projection:planar_xy,planar_xz,planar_yz,cylindrical(Z axis),spherical,triplanar(default), orcubic.amplitude_mm: signed displacement at white, default 0.3. Black is zero. Negative values engrave.symmetric: trueinstead maps brightness to [-0.5, +0.5] times amplitude.invert: truereverses brightness first.RGB textures are converted to 8-bit grayscale using weighted encoded sRGB channels (0.2126 R + 0.7152 G + 0.0722 B); alpha is ignored. Upstream samples the resulting red channel with tiled bilinear interpolation. This preserves upstream behavior for grayscale maps; color handling is explicitly defined by this adapter.
tile_size_mm: nominal square repeat size, default 5. The core preserves image aspect ratio, so a non-square image produces a proportionally shorter tile on its short axis.offset_u/offset_vare texture cycles;rotation_degrotates projection coordinates.refine_length_mm: target maximum edge length before displacement, default 0.5. Smaller values increase memory and work.max_trianglesis a soft output target after subdivision, not a memory cap; masks and repair can exceed it.exclude_bottom_degandexclude_top_deg: exclude faces whose normals are within the given angle of -Z/+Z. Zero disables each mask. Shared mask-boundary vertices are pinned by the core.boundary_falloff_mmtapers displacement near masked boundaries. This does not protect arbitrary holes, threads, or vertical mating surfaces.Regularization and flat-face harvesting are disabled in this minimal adapter. Decimation and upstream T-junction repair run only when the output exceeds the triangle target.
The schema returned by tools/list is authoritative for defaults and ranges. Results include the normalized parameters, before/after measurements, output path, byte count, SHA-256, and warnings. Files with degenerate triangles can be inspected but must be repaired before texturing.
Codex connection
Build first. Replace both paths below with absolute paths on the machine where Codex runs. Use command -v node to locate Node if a desktop launcher has a different PATH.
codex mcp add bumpmesh -- /absolute/path/to/node /absolute/path/to/bumpmesh-mcp/dist/index.js --root /absolute/path/to/3d-files
codex mcp listEquivalent scoped entry in ~/.codex/config.toml (preserve all existing entries):
[mcp_servers.bumpmesh]
command = "/absolute/path/to/node"
args = ["/absolute/path/to/bumpmesh-mcp/dist/index.js", "--root", "/absolute/path/to/3d-files"]
startup_timeout_sec = 20
tool_timeout_sec = 150The CLI command saves the server but does not prove the active task loaded it. Reload MCP connections or start a new task as required by your client. For a connection-only check, discover the three tools and call list_supported_formats; no model mutation is needed. The project tests separately prove successful mesh processing on disposable fixtures.
Official reference: Codex MCP configuration.
ChatGPT / Streamable HTTP
This server also implements stateless Streamable HTTP:
BUMPMESH_ROOT=/absolute/path/to/3d-files node dist/index.js --http --port 3000Endpoint: http://127.0.0.1:3000/mcp. It binds only to loopback, rejects browser Origin headers and unexpected Host headers, and supports optional BUMPMESH_HTTP_TOKEN bearer authentication. It is not an OAuth authorization server.
ChatGPT's web developer mode connects to remote SSE/Streamable HTTP endpoints, not this machine's stdio or localhost. For a real ChatGPT connection:
Run the HTTP server on the host holding the intended files, with a dedicated root folder.
Put it behind an HTTPS endpoint with an MCP-compatible OAuth gateway. The gateway must validate users, forward requests to loopback, rewrite Host to
127.0.0.1:3000, and avoid forwarding browser Origin. It can injectBUMPMESH_HTTP_TOKENas an upstream bearer token. Allow requests lasting at least 150 seconds. OAuth/gateway deployment is not included here.Enable ChatGPT Developer mode in Settings, create an app for the public HTTPS
/mcpendpoint, and configure OAuth for that gateway. The UI and account eligibility are described in the official link below. ChatGPT does not document a generic static-bearer connector mode; do not assume the server's token environment variable alone supplies ChatGPT authentication.Select the app, discover tools, and call
list_supported_formatsto verify the root and formats. Files must already exist on the server host; ChatGPT attachments are not automatically synchronized. The current API returns paths and metadata, not downloadable attachments.
For a short disposable test, ChatGPT also supports No Authentication, but this would expose the selected folder's MCP operations to anyone who reaches the endpoint. Use only generated fixtures in an isolated environment, then stop the endpoint. No tunnel or public service is started by this project.
Local HTTP protocol behavior is covered by integration tests. A live ChatGPT connection, gateway authentication, and remote file delivery have not been tested or deployed.
Official reference: ChatGPT Developer mode (remote transports and OAuth/No Authentication).
Agent skill
The instruction-only skill is skills/bumpmesh-texturing/SKILL.md. It covers projection/height semantics, fit boundaries, inspection, error recovery, and evidence limits. It needs this MCP server, not another runtime or paid API.
To install for Codex, copy its folder to your skill directory (do not overwrite an existing customized copy):
mkdir -p "${CODEX_HOME:-$HOME/.codex}/skills"
cp -R skills/bumpmesh-texturing "${CODEX_HOME:-$HOME/.codex}/skills/"Reload skills/start a new task if required. Invoke $bumpmesh-texturing with the local model and height-map paths. Other MCP clients can use the same workflow as instructions; installing a local Codex skill does not automatically install it in ChatGPT web.
Limits and failure behavior
Required explicit file root; inputs and outputs must remain inside it, including resolved symlinks. Parent output folders must already exist. Existing files, including dangling symlinks, are never replaced.
One mesh job at a time; concurrent jobs receive
BUSY. Jobs run in a worker with a 120-second timeout and a 768 MiB V8 old-generation limit. Native allocations and typed-array buffers are not covered by that heap limit; this is not an OS sandbox or a total RAM guarantee.32 MiB model files, 16 MiB texture files, 4096² decoded pixels, 100,000 input triangles. Subdivision progress is checked against 500,000 intermediate triangles; a subdivision iteration can allocate beyond the threshold before the callback aborts. Very large or adversarial inputs should use separate process/container memory limits.
Output publication uses a same-directory temporary file and an exclusive hard link. Cancellation before publication removes the temporary file; cancellation after the atomic publication point cannot undo the completed output. Abrupt process termination can leave a
.bumpmesh-*.tmpfile. Local filesystems supporting hard links are required.TIMEOUT/MESH_BUDGET_EXCEEDED: increaserefine_length_mm; reducing the final decimation target does not reduce subdivision work.OUTPUT_EXISTS: choose a new filename.DEGENERATE_GEOMETRY: repair the input.Edge diagnostics weld at 0.0001 mm and do not test self-intersection, orientation consistency, slicer toolpaths, printer behavior, or physical fit. Inspect output in a slicer before printing. Input OBJ scene details and source 3MF printer settings are not preserved.
Source, license, and maintenance
Pinned upstream: a6ac179149b8a17c71a9469dd4cb6f866c0c01d1, inspected 2026-09-23 (upstream commit dated 2026-07-23, v1.2.0). UPSTREAM.md records the reused modules and exact adaptation.
This combined work is AGPL-3.0-only, retaining CNC Kitchen / Stefan Hermann and contributors' notices; see LICENSE. The vendored source and adapter source are included. If distributing binaries or offering a modified network service, provide the corresponding source under the applicable AGPL terms, including its network-interaction source requirement. A private development repository is not itself a source offer to external service users.
Three.js, fflate, Zod, and the MCP SDK use MIT licenses. Sharp uses Apache-2.0 and bundles native components with their own notices (including libvips); retain dependency license notices when redistributing installed binaries.
src/engine.ts contains reusable domain logic, src/server.ts tools, src/index.ts transports, and src/runner.ts worker lifecycle. To update upstream, compare the selected modules, keep the pristine sources and license notices, regenerate nodeExporter.js, update the commit/hash manifest deliberately, and rerun geometry and protocol tests. Do not replace the core with an approximate reimplementation.
Available Tools
3 toolsapply_textureA
Subdivide a local STL/OBJ, displace its surface using a PNG/JPEG/WebP height map, optionally decimate, and export a new STL/3MF. Use after inspect_model. Preserves input coordinates. Never overwrites files. Negative amplitude engraves. No network downloads or browser automation.
| Name | Required | Description | Default |
|---|---|---|---|
| invert | No | Invert image brightness before displacement. | |
| offset_u | No | Offset in texture cycles. | |
| offset_v | No | ||
| symmetric | No | Center brightness at 0.5; displacement range is +/- half amplitude. | |
| model_path | Yes | Absolute path or path relative to the configured BUMPMESH_ROOT. | |
| projection | No | triplanar | |
| output_path | Yes | New .stl or .3mf file inside BUMPMESH_ROOT. Parent directory must exist; overwriting is forbidden. | |
| amplitude_mm | No | Signed displacement at white; black is zero unless symmetric=true. Negative values engrave. | |
| rotation_deg | No | ||
| texture_path | Yes | ||
| tile_size_mm | No | Nominal square tile size; upstream preserves the image aspect ratio. | |
| max_triangles | No | Soft decimation target, not a memory limit; repairs can increase final count. | |
| exclude_top_deg | No | Exclude faces within this angle of +Z. Zero disables. | |
| refine_length_mm | No | Target maximum edge length before displacement. Smaller values cost more memory. | |
| exclude_bottom_deg | No | Exclude faces within this angle of -Z. Zero disables. Assumes Z-up. | |
| boundary_falloff_mm | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already indicate non-readonly and non-destructive behavior, so the bar for adding context is met by specific behavioral details: it preserves input coordinates, never overwrites files, negative amplitude engraves, and performs no network or browser actions. These descriptions go beyond the structured hints and clarify side effects and safety boundaries.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description packs the core workflow into one dense sentence and adds only high-value supplementary notes in short, scannable clauses. There is no filler or repetition.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a complex 16-parameter tool with no output schema, it covers the key invocation context: file handling, coordinate preservation, safety, ordering relative to inspect_model, and engraving semantics. It could be more explicit about return value or on-screen output, but given no output schema exists, the description still provides enough to call and interpret the tool reasonably.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 69%, leaving parameters like offset_v, rotation_deg, and boundary_falloff_mm without schema docs. The description adds thematic context (e.g., 'Negative amplitude engraves' for amplitude_mm; 'optionally decimate' for max_triangles) but does not systematically compensate for the undocumented parameters, so it matches the baseline for partial coverage.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a specific action sequence (subdivide, displace, decimate, export) and lists concrete input/output formats (STL/OBJ, PNG/JPEG/WebP, STL/3MF). It clearly differentiates itself from sibling tools list_supported_formats and inspect_model by describing a transformation workflow.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description tells agents to use this after inspect_model, which establishes an expected pipeline sequence. It also states it works on local files ('local STL/OBJ', 'no network downloads or browser automation'), distinguishing it from anything remote. However, it does not explicitly state when not to use it or mention alternative tools by name.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
inspect_modelARead-only
Inspect a local STL/OBJ before texturing: triangles, millimeter bounds, open and non-manifold edges. Does not modify the model.
| Name | Required | Description | Default |
|---|---|---|---|
| model_path | Yes | Absolute path or path relative to the configured BUMPMESH_ROOT. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The annotations already declare readOnlyHint=true, and the description reinforces this with 'Does not modify the model' while adding what exactly is inspected. It does not cover failure modes or return format, but for a safe read-only inspection tool this is acceptable.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two compact sentences with no filler. The first sentence front-loads the action and scope, and the second delivers the key non-mutation guarantee. Every phrase earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a single-parameter read-only tool, the description covers purpose, parameter expectations, and non-modifying behavior. With no output schema, it hints at return content via 'triangles, millimeter bounds, open and non-manifold edges', but it could explicitly state output format or error behavior.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema covers model_path semantics at 100% by describing absolute or BUMPMESH_ROOT-relative paths. The description adds value by restricting the file type to local STL/OBJ, which is not present in the schema and helps disambiguate the parameter's expected input.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb ('Inspect'), identifies the resource ('local STL/OBJ before texturing'), and lists concrete outputs (triangles, millimeter bounds, open and non-manifold edges). It clearly differentiates from the siblings apply_texture and list_supported_formats by focusing on geometry validation rather than modification or format listing.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The phrase 'before texturing' provides a clear workflow context, indicating this tool is the prerequisite to apply_texture. It doesn't explicitly name alternatives or state exclusions, but the intended use case is evident and distinct from list_supported_formats.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_supported_formatsARead-only
List supported model/texture/export formats, processing limits, units, and the configured local file root.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, so the safety profile is covered. The description adds context by enumerating what data will be surfaced (formats, limits, units, file root), but it does not disclose details like whether the list is complete, how results are structured, or whether the file root is resolved at call time. This is adequate, not exceptional.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single sentence that is front-loaded with the action verb and efficiently lists all result categories without redundancy or filler. Every word earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a no-parameter, read-only list tool, the description fully specifies what an agent will receive: supported formats, processing limits, units, and local file root. No output schema exists, but the enumerated result categories are sufficient for an agent to decide whether to call the tool and what to expect.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
With zero parameters and an empty schema, there is nothing to document. The schema coverage is 100%, so the baseline of 4 applies; the description adds value by clarifying that the tool returns environment/capability information rather than taking input.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb, 'List', and names the exact resource categories: model/texture/export formats, processing limits, units, and the configured local file root. This is distinct from the sibling tools (inspect_model, apply_texture), which clearly inspect or mutate model data rather than enumerate tool capabilities.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The intended usage is implied by the purpose: call this when you need to know supported formats or environment configuration. However, the description gives no explicit when-to-use guidance or comparisons with sibling tools such as inspect_model, so an agent must infer when this is the right choice versus inspecting a specific model.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
3 tool updates
v0.1.0- First observed
apply_texture - First observed
inspect_model - First observed
list_supported_formats
TDQS
Scored across 3 tools
Each tool has a clearly distinct role: listing supported formats/configuration, inspecting a model, and applying a texture operation. There is no overlap or ambiguity in their purposes.
All tool names follow a consistent snake_case verb-first pattern: list_supported_formats, inspect_model, apply_texture. The naming style is uniform and predictable.
Three tools is a well-scoped set for a focused single-purpose server. Each tool occupies a necessary step in the local mesh texturing workflow with no redundant additions.
The tool surface covers the full intended pipeline: discover supported formats, inspect the input model, and apply a heightmap texture with export options. There are no obvious dead ends or missing operations for the stated domain.
Maintenance
Related MCP Connectors
- OwlCADOAuthcom.owlcad
Parametric 3D CAD for AI agents: build print-ready parts, check them, export STL, 3MF or STEP.
Cloud Blender for AI agents: scenes, assets, renders, MP4, STL, GLB — over hosted remote MCP.
Free text/image → 3D: generate, rig, avatar-ify, and refine GLB models. No auth, no payment.
3D avatar/asset foundry: text/image -> rigged, validated, engine-ready GLB via x402.
Related MCP Servers
AlicenseNot gradedqualityCmaintenanceEnables 3D model generation via natural language, supporting text-to-3D and image-to-3D with remote or local deployment options.MIT- AlicenseNot gradedqualityBmaintenanceEnables AI agents to process images locally via file paths—converting, resizing, removing backgrounds, smart cropping, upscaling, reading or stripping metadata, and batch processing—without files ever leaving the device.MIT
- AlicenseAqualityCmaintenanceEnables AI agents to generate game-ready 3D assets from reference images with PBR textures, and to retexture meshes the user already owns, while recording full provenance for every generated file.2010MIT
- FlicenseAqualityBmaintenanceEnables AI assistants to perform high-performance 3D CAD design, ultra-fast multi-view rendering, immutable versioned project management, and geometry/mesh verification for 3D printing on Windows.17-