substance-painter-mcp
Enables conversational control of Adobe Substance 3D Painter for look-dev iteration, including baking, smart materials, and generator parameter tuning.
README
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.
Install
1. Install the bridge plugin into Painter
python scripts/install_plugin.py
This 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:60043
3. Install the MCP server
python -m venv .venv
.venv/Scripts/python -m pip install -e . # .venv/bin/python on macOS/Linux
4. 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 |
|---|---|---|
SP_MCP_BRIDGE_HOST |
127.0.0.1 |
Bind/connect address |
SP_MCP_BRIDGE_PORT |
60043 |
Bridge port |
SP_MCP_BRIDGE_TIMEOUT |
600 |
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 |
|---|---|
painter_status |
Reachability and version check |
painter_project_info / painter_create_project / painter_open_project / painter_save_project |
Project lifecycle |
painter_search_resources |
Find smart materials, generators, masks, export presets |
painter_get_baking_parameters / painter_set_baking_parameters |
Inspect and set bake settings, including high-poly path and cage distance |
painter_bake / painter_baking_status |
Bake mesh maps (async, with optional wait) |
painter_layer_tree |
Read the layer stack; every node has a uid |
painter_insert_smart_material |
Instantiate a shelf smart material |
painter_insert_layer / painter_insert_generator / painter_add_mask |
Build stacks |
painter_set_fill_source / painter_import_resource |
Assign a bitmap or flat colour to a fill layer's channel |
painter_set_layer / painter_delete_layer |
Name, visibility, opacity, blending mode; delete |
painter_screenshot |
Capture the viewport — see the result instead of inferring it |
painter_get_parameters / painter_set_parameters / painter_apply_preset |
Tune generators — the look-dev loop |
painter_list_export_presets / painter_export_textures |
Export maps |
painter_list_ops / painter_call / painter_exec |
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 did
painter_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 API
The 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 project
reload_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.
推荐服务器
Baidu Map
百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
Playwright MCP Server
一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。
Magic Component Platform (MCP)
一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。
Audiense Insights MCP Server
通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。
VeyraX
一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。
graphlit-mcp-server
模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。
Kagi MCP Server
一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。
e2b-mcp-server
使用 MCP 通过 e2b 运行代码。
Neon MCP Server
用于与 Neon 管理 API 和数据库交互的 MCP 服务器
Exa MCP Server
模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。