dcc-mcp-nuke 0.2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- dcc_mcp_nuke/__init__.py +4 -0
- dcc_mcp_nuke/__version__.py +1 -0
- dcc_mcp_nuke/dispatcher.py +23 -0
- dcc_mcp_nuke/nuke_plugin/init.py +5 -0
- dcc_mcp_nuke/plugin.py +9 -0
- dcc_mcp_nuke/server.py +52 -0
- dcc_mcp_nuke/skills/nuke-script/SKILL.md +20 -0
- dcc_mcp_nuke/skills/nuke-script/scripts/inspect_script.py +16 -0
- dcc_mcp_nuke/skills/nuke-script/scripts/list_nodes.py +9 -0
- dcc_mcp_nuke/skills/nuke-script/scripts/save_script.py +15 -0
- dcc_mcp_nuke/skills/nuke-script/tools.yaml +34 -0
- dcc_mcp_nuke-0.2.0.dist-info/METADATA +43 -0
- dcc_mcp_nuke-0.2.0.dist-info/RECORD +16 -0
- dcc_mcp_nuke-0.2.0.dist-info/WHEEL +4 -0
- dcc_mcp_nuke-0.2.0.dist-info/entry_points.txt +2 -0
- dcc_mcp_nuke-0.2.0.dist-info/licenses/LICENSE +9 -0
dcc_mcp_nuke/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.2.0" # x-release-please-version
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"""Nuke's native main-thread bridge."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import threading
|
|
6
|
+
from typing import Any, Callable
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class NukeDispatcher:
|
|
10
|
+
"""Route core skill calls into Nuke without managing a second queue."""
|
|
11
|
+
|
|
12
|
+
def dispatch_callable(self, func: Callable[..., Any], *args: Any, **kwargs: Any) -> Any:
|
|
13
|
+
kwargs.pop("context", None)
|
|
14
|
+
kwargs.pop("action_name", None)
|
|
15
|
+
kwargs.pop("skill_name", None)
|
|
16
|
+
kwargs.pop("execution", None)
|
|
17
|
+
kwargs.pop("timeout_hint_secs", None)
|
|
18
|
+
kwargs.pop("affinity", kwargs.pop("thread_affinity", None))
|
|
19
|
+
if threading.current_thread() is threading.main_thread():
|
|
20
|
+
return func(*args, **kwargs)
|
|
21
|
+
import nuke # Lazy import: requires a running Nuke process.
|
|
22
|
+
|
|
23
|
+
return nuke.executeInMainThreadWithResult(func, args, kwargs)
|
dcc_mcp_nuke/plugin.py
ADDED
dcc_mcp_nuke/server.py
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import Optional
|
|
6
|
+
|
|
7
|
+
from dcc_mcp_core import DccServerOptions, HostExecutionBridge
|
|
8
|
+
from dcc_mcp_core.server_base import DccServerBase
|
|
9
|
+
|
|
10
|
+
from dcc_mcp_nuke.__version__ import __version__
|
|
11
|
+
from dcc_mcp_nuke.dispatcher import NukeDispatcher
|
|
12
|
+
|
|
13
|
+
DEFAULT_PORT = 8765
|
|
14
|
+
SERVER_NAME = "dcc-mcp-nuke"
|
|
15
|
+
_server: Optional["NukeMcpServer"] = None
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class NukeMcpServer(DccServerBase):
|
|
19
|
+
def __init__(self, port: int = DEFAULT_PORT) -> None:
|
|
20
|
+
options = DccServerOptions.from_env(
|
|
21
|
+
"nuke",
|
|
22
|
+
Path(__file__).resolve().parent / "skills",
|
|
23
|
+
port=port,
|
|
24
|
+
server_name=SERVER_NAME,
|
|
25
|
+
server_version=__version__,
|
|
26
|
+
execution_bridge=HostExecutionBridge(dispatcher=NukeDispatcher()),
|
|
27
|
+
)
|
|
28
|
+
super().__init__(options=options)
|
|
29
|
+
|
|
30
|
+
def _version_string(self) -> str:
|
|
31
|
+
try:
|
|
32
|
+
import nuke
|
|
33
|
+
|
|
34
|
+
return str(nuke.env.get("NukeVersionString", "Nuke"))
|
|
35
|
+
except Exception:
|
|
36
|
+
return "Nuke"
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def start_server(port: Optional[int] = None) -> NukeMcpServer:
|
|
40
|
+
global _server
|
|
41
|
+
if _server is None or not _server.is_running:
|
|
42
|
+
_server = NukeMcpServer(port or int(os.environ.get("DCC_MCP_NUKE_PORT", DEFAULT_PORT)))
|
|
43
|
+
_server.register_builtin_actions()
|
|
44
|
+
_server.start()
|
|
45
|
+
return _server
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def stop_server() -> None:
|
|
49
|
+
global _server
|
|
50
|
+
if _server is not None:
|
|
51
|
+
_server.stop()
|
|
52
|
+
_server = None
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: nuke-script
|
|
3
|
+
description: >-
|
|
4
|
+
Host skill - inspect and explicitly save the active Nuke script. Use when
|
|
5
|
+
checking root settings, selected nodes, or saving a known path. Not for raw Python execution.
|
|
6
|
+
license: MIT
|
|
7
|
+
compatibility: "Nuke Python API; dcc-mcp-core 0.19+"
|
|
8
|
+
allowed-tools: Python
|
|
9
|
+
metadata:
|
|
10
|
+
dcc-mcp:
|
|
11
|
+
dcc: nuke
|
|
12
|
+
version: "0.0.0"
|
|
13
|
+
layer: domain
|
|
14
|
+
stage: scene
|
|
15
|
+
search-hint: "nuke script root selected nodes inspect save nk"
|
|
16
|
+
tags: "nuke, compositing, nodes, script"
|
|
17
|
+
tools: tools.yaml
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
# Nuke Script
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
from dcc_mcp_core.skill import skill_entry, skill_success
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
@skill_entry
|
|
5
|
+
def main(**_kwargs):
|
|
6
|
+
import nuke # Lazy import: requires Nuke.
|
|
7
|
+
|
|
8
|
+
root = nuke.root()
|
|
9
|
+
selected = nuke.selectedNodes()
|
|
10
|
+
return skill_success(
|
|
11
|
+
"Inspected Nuke script",
|
|
12
|
+
path=nuke.scriptName(),
|
|
13
|
+
first_frame=root["first_frame"].value(),
|
|
14
|
+
last_frame=root["last_frame"].value(),
|
|
15
|
+
selected_nodes=[node.name() for node in selected],
|
|
16
|
+
)
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
from dcc_mcp_core.skill import skill_entry, skill_success
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
@skill_entry
|
|
5
|
+
def main(**_kwargs):
|
|
6
|
+
import nuke # Lazy import: requires Nuke.
|
|
7
|
+
|
|
8
|
+
nodes = [{"name": node.name(), "class": node.Class()} for node in nuke.allNodes(recurseGroups=True)]
|
|
9
|
+
return skill_success("Listed Nuke nodes", node_count=len(nodes), nodes=nodes)
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
from dcc_mcp_core.skill import skill_entry, skill_error, skill_success
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@skill_entry
|
|
7
|
+
def main(path: str, **_kwargs):
|
|
8
|
+
import nuke # Lazy import: requires Nuke.
|
|
9
|
+
|
|
10
|
+
target = Path(path).expanduser().resolve()
|
|
11
|
+
if target.suffix.lower() != ".nk":
|
|
12
|
+
return skill_error("Nuke script path must end in .nk", str(target))
|
|
13
|
+
target.parent.mkdir(parents=True, exist_ok=True)
|
|
14
|
+
nuke.scriptSaveAs(str(target))
|
|
15
|
+
return skill_success("Saved Nuke script", path=str(target))
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
tools:
|
|
2
|
+
- name: inspect_script
|
|
3
|
+
description: Inspect the active Nuke script, frame range, and selected nodes without changing it.
|
|
4
|
+
input_schema: {type: object, properties: {}}
|
|
5
|
+
read_only: true
|
|
6
|
+
destructive: false
|
|
7
|
+
idempotent: true
|
|
8
|
+
execution: sync
|
|
9
|
+
affinity: main
|
|
10
|
+
timeout_hint_secs: 15
|
|
11
|
+
source_file: scripts/inspect_script.py
|
|
12
|
+
- name: list_nodes
|
|
13
|
+
description: List nodes in the current Nuke script without modifying it.
|
|
14
|
+
input_schema: {type: object, properties: {}}
|
|
15
|
+
read_only: true
|
|
16
|
+
destructive: false
|
|
17
|
+
idempotent: true
|
|
18
|
+
execution: sync
|
|
19
|
+
affinity: main
|
|
20
|
+
timeout_hint_secs: 30
|
|
21
|
+
source_file: scripts/list_nodes.py
|
|
22
|
+
- name: save_script
|
|
23
|
+
description: Save the current Nuke script to an explicit absolute .nk path.
|
|
24
|
+
input_schema:
|
|
25
|
+
type: object
|
|
26
|
+
required: [path]
|
|
27
|
+
properties: {path: {type: string, description: Absolute .nk output path.}}
|
|
28
|
+
read_only: false
|
|
29
|
+
destructive: true
|
|
30
|
+
idempotent: false
|
|
31
|
+
execution: sync
|
|
32
|
+
affinity: main
|
|
33
|
+
timeout_hint_secs: 60
|
|
34
|
+
source_file: scripts/save_script.py
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: dcc-mcp-nuke
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Nuke adapter for the DCC Model Context Protocol ecosystem
|
|
5
|
+
Project-URL: Homepage, https://github.com/dcc-mcp/dcc-mcp-nuke
|
|
6
|
+
Project-URL: Repository, https://github.com/dcc-mcp/dcc-mcp-nuke
|
|
7
|
+
Project-URL: Issues, https://github.com/dcc-mcp/dcc-mcp-nuke/issues
|
|
8
|
+
Author-email: Long Hao <hal.long@outlook.com>
|
|
9
|
+
License: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Topic :: Multimedia :: Graphics
|
|
19
|
+
Requires-Python: >=3.9
|
|
20
|
+
Requires-Dist: dcc-mcp-core<1.0.0,>=0.19.3
|
|
21
|
+
Provides-Extra: dev
|
|
22
|
+
Requires-Dist: build; extra == 'dev'
|
|
23
|
+
Requires-Dist: pytest>=7; extra == 'dev'
|
|
24
|
+
Requires-Dist: pyyaml>=6; extra == 'dev'
|
|
25
|
+
Requires-Dist: ruff>=0.8; extra == 'dev'
|
|
26
|
+
Requires-Dist: twine; extra == 'dev'
|
|
27
|
+
Description-Content-Type: text/markdown
|
|
28
|
+
|
|
29
|
+
# dcc-mcp-nuke
|
|
30
|
+
|
|
31
|
+
Nuke adapter for the DCC Model Context Protocol. It embeds a Streamable HTTP
|
|
32
|
+
MCP server in Nuke and uses Nuke's main-thread execution API for scene tools.
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
python -m pip install dcc-mcp-nuke
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Add the installed package's `dcc_mcp_nuke/nuke_plugin` folder to `NUKE_PATH`.
|
|
39
|
+
Nuke loads its `init.py` and serves MCP at `http://127.0.0.1:8765/mcp`.
|
|
40
|
+
|
|
41
|
+
The bundled `nuke-script` skill inspects scripts and nodes and can explicitly
|
|
42
|
+
save the current script. Releases are published through `release.yaml` and the
|
|
43
|
+
GitHub `pypi` environment.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
dcc_mcp_nuke/__init__.py,sha256=pJPRhFpt6tUTkJcr1dySrvzcORoJa5uLmD_wFCPGaF8,197
|
|
2
|
+
dcc_mcp_nuke/__version__.py,sha256=piZV5NEcs0VIotCxwaWvzWE2ASUv5tox5ye8ogIRiIk,50
|
|
3
|
+
dcc_mcp_nuke/dispatcher.py,sha256=zZ20u9JYy5M7v-Mf7_bLQMWH6wxDFsH1JWvK5EP7tGA,835
|
|
4
|
+
dcc_mcp_nuke/plugin.py,sha256=4wJP4F-iXTRW1uW69ixYrqkQbETAh_0nUnBV3lfOwIk,149
|
|
5
|
+
dcc_mcp_nuke/server.py,sha256=5GUzsDsGD8og9D4o8iIH6sJChAQo15AR-UOV0Hjq-9M,1488
|
|
6
|
+
dcc_mcp_nuke/nuke_plugin/init.py,sha256=CJNieOo3yc2xwuYg7My7QNO8e2hlb22ei_HkNGe1bbc,113
|
|
7
|
+
dcc_mcp_nuke/skills/nuke-script/SKILL.md,sha256=hZ11FmVhbi001bkMKywULNY8GxMWrRHgpg8xPgm2bME,542
|
|
8
|
+
dcc_mcp_nuke/skills/nuke-script/tools.yaml,sha256=YGxIZp985MHlZvmFt8SdppNaRpVl8VBMkgMZ75DlAS4,1083
|
|
9
|
+
dcc_mcp_nuke/skills/nuke-script/scripts/inspect_script.py,sha256=D0dLOp5nVMFlIoqEXqORZ4WS_xExpRsQqAjJIs0ksNU,453
|
|
10
|
+
dcc_mcp_nuke/skills/nuke-script/scripts/list_nodes.py,sha256=U4dqinKE93YHyV2pYUhgcTvzeydIOmoQli720Y8le_s,329
|
|
11
|
+
dcc_mcp_nuke/skills/nuke-script/scripts/save_script.py,sha256=maenEJ8kWjixqB6MgF12EhOiwr7mABqWs_oWfkbEklw,506
|
|
12
|
+
dcc_mcp_nuke-0.2.0.dist-info/METADATA,sha256=0tJmWrs5AOKjyeB3TMwD2PotJxSg5DHOol8Nerep9F8,1669
|
|
13
|
+
dcc_mcp_nuke-0.2.0.dist-info/WHEEL,sha256=lCkmxWfQsSc9CfIClYeavTdQeEX2toPqufh9gI35EQA,87
|
|
14
|
+
dcc_mcp_nuke-0.2.0.dist-info/entry_points.txt,sha256=BaI7AcPJRcegrynY2qIMPZ9afymICwbJwQbh7PEaSHc,53
|
|
15
|
+
dcc_mcp_nuke-0.2.0.dist-info/licenses/LICENSE,sha256=FAZJ20BbkJ0ImRGTUsVtociFnXF77FdkW0QfZQ1ggis,806
|
|
16
|
+
dcc_mcp_nuke-0.2.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Long Hao
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
6
|
+
|
|
7
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|