substance-painter-mcp
Click on "Install 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., "@substance-painter-mcpbake ambient occlusion for the high-poly model"
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.
substance-painter-mcp
An MCP server for driving Adobe Substance 3D Painter conversationally — bake mesh maps, stack smart materials, and tune generator parameters by talking to the app instead of guessing weights and re-baking.
Built for look-dev iteration, where weathering is authored by taste against a reference rather than by fixed numbers.
Requirements
Substance 3D Painter 12.x (developed against 12.1.1 / Python API 0.3.5), running
Python 3.10+ for the MCP server
Windows, macOS and Linux. No launch flags and no --enable-remote-scripting — Painter can
be started normally. If you have no Python installed, Painter bundles a complete CPython
3.13 at <install>/resources/pythonsdk/python.exe that works fine.
Related MCP server: Maya MCP Server
Install
1. Install the bridge plugin into Painter
python scripts/install_plugin.pyThis copies painter_plugin/substance_painter_mcp_bridge into Painter's user plugin
folder, <Documents>/Adobe/Adobe Substance 3D Painter/python/plugins/. On Windows the
Documents location is read from the shell-folder registry, so OneDrive redirection and
moved Documents folders are handled; pass --plugins-dir to override.
Use --link to symlink instead of copy while developing (needs Developer Mode or an
elevated shell on Windows), and --uninstall to remove it.
2. Enable it in Painter
Python → Reload Plugins Folder, then tick substance_painter_mcp_bridge under
Python → Plugins.
This step is required. Painter treats everything in
python/plugins/as an optional component: modules are discovered but not started until enabled. Onlypython/startup/loads automatically. Painter remembers the choice, so this is one-time — but a fresh install that skips it will simply never open the port.
Prefer no UI step? python scripts/install_plugin.py --startup installs into
startup/ instead, which always loads, at the cost of losing the on/off toggle.
Either way the log window should show:
[substance-painter-mcp] listening on 127.0.0.1:600433. Install the MCP server
python -m venv .venv
.venv/Scripts/python -m pip install -e . # .venv/bin/python on macOS/Linux4. Register it with your MCP client
{
"mcpServers": {
"substance-painter": {
"command": "C:/Users/you/code/substance-painter-mcp/.venv/Scripts/python.exe",
"args": ["-m", "substance_painter_mcp"]
}
}
}Then call painter_status — it distinguishes "Painter isn't running" from "that
operation was invalid", so it's the right first thing to try when something fails.
Configuration
Variable | Default | Meaning |
|
| Bind/connect address |
|
| Bridge port |
|
| Client socket timeout, seconds |
The bridge binds to loopback only. It executes arbitrary Python inside Painter by design
(painter_exec), so do not expose the port beyond localhost.
Tools
Tool | Purpose |
| Reachability and version check |
| Project lifecycle |
| Find smart materials, generators, masks, export presets |
| Inspect and set bake settings, including high-poly path and cage distance |
| Bake mesh maps (async, with optional wait) |
| Read the layer stack; every node has a |
| Instantiate a shelf smart material |
| Build stacks |
| Assign a bitmap or flat colour to a fill layer's channel |
| Name, visibility, opacity, blending mode; delete |
| Capture the viewport — see the result instead of inferring it |
| Tune generators — the look-dev loop |
| Export maps |
| Escape hatches |
The tuning loop
painter_get_parameters is the tool that makes conversational iteration work. It returns
each parameter's key, human label, widget type, current value and enum options, so the
model discovers that a rust generator exposes Dirt Level rather than guessing at names:
painter_layer_tree() → find the generator's uid
painter_get_parameters(uid=42) → see what knobs exist
painter_set_parameters(uid=42, '{"Dirt Level": 0.7}')
painter_screenshot() → look at what that didpainter_screenshot closes the loop. Without it the model is editing blind and has to
trust that a parameter did what it claims; with it, each change can actually be checked.
A smart material is a group of layers, so tuning one means walking into the group and
adjusting the generator effects inside it. painter_layer_tree returns the full
hierarchy with uids in a single call for that reason.
Wear is driven by the baked mesh maps via generators — mg_metal_edge_wear for edges and
bolts, mg_dirt for crevices, mg_position multiplied into a mask to bias wear
vertically. Mask effects blend with each other, which is how "heavier down low, lighter
up top" gets expressed.
How it works
Claude ──stdio──> MCP server (this repo, any Python)
│
│ newline-delimited JSON over TCP, loopback only
▼
Bridge plugin (runs inside Painter, Qt server on the main thread)
│
▼
substance_painter Python APIThe bridge is a Painter plugin rather than the --enable-remote-scripting HTTP
endpoint, for two reasons:
No launch flag. Painter can be started normally, including from Creative Cloud.
Thread affinity. The
substance_painterAPI is only safe to call from the main/UI thread. A QtQTcpServercreated inside the plugin lives on Painter's own event loop, so every request handler already runs on the right thread — no cross-thread marshalling and no temp-file result passing.
Wire protocol
Newline-delimited JSON, one object per line:
→ {"id": 1, "op": "layers.tree", "params": {"deep": true}}
← {"id": 1, "ok": true, "result": {...}}
← {"id": 1, "ok": false, "error": {"kind": "no_project", "message": "..."}}json.dumps escapes newlines inside strings, so a serialised message never contains a
raw newline of its own and the framing is safe.
Development
.venv/Scripts/python -m pytest # protocol tests, no Painter needed
.venv/Scripts/python -m ruff check .tests/ runs the bridge client against a fake NDJSON server, so framing, error mapping
and reconnect-after-plugin-reload are covered without the application installed. Anything
touching the substance_painter API needs Painter running.
Against a running Painter:
python scripts/smoke_test.py # exercise the bridge end to end
python scripts/reload_plugin.py # hot-reload after editing the plugin
python scripts/smoke_test.py --mesh mesh.fbx --force # also create a projectreload_plugin.py avoids a Painter restart on every edit. Install the plugin with
--link so the files are already in place and only the reload is needed.
Notes and limitations
Baking is asynchronous. API 0.3.5 has no synchronous
bake(), onlybake_async. The bridge tracks progress through Painter'sBakingProcessProgress/BakingProcessEndedevents andpainter_bakepolls to completion by default.Cage distance matters on meshes with overlapping shells. Cage distances are relative to the bounding box by default, and a generous cage samples interior surfaces and produces black patches. Read the real key names with
painter_get_baking_parametersbefore setting them — they come from Painter, not from this server.One bake at a time. The bridge rejects a second concurrent bake.
See docs/api-findings.md for what was verified against the installed SDK, including several silent-failure modes worth knowing about.
License
MIT — see LICENSE.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/jwang47/substance-painter-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server