dcc-mcp-touchdesigner 0.1.0__tar.gz

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.
Files changed (40) hide show
  1. dcc_mcp_touchdesigner-0.1.0/.github/scripts/start_mcp_server.py +42 -0
  2. dcc_mcp_touchdesigner-0.1.0/.github/workflows/ci.yml +59 -0
  3. dcc_mcp_touchdesigner-0.1.0/.github/workflows/release.yml +68 -0
  4. dcc_mcp_touchdesigner-0.1.0/.gitignore +32 -0
  5. dcc_mcp_touchdesigner-0.1.0/.release-please-manifest.json +3 -0
  6. dcc_mcp_touchdesigner-0.1.0/CHANGELOG.md +18 -0
  7. dcc_mcp_touchdesigner-0.1.0/PKG-INFO +129 -0
  8. dcc_mcp_touchdesigner-0.1.0/README.md +96 -0
  9. dcc_mcp_touchdesigner-0.1.0/install.md +123 -0
  10. dcc_mcp_touchdesigner-0.1.0/packaging/assemble_release.py +69 -0
  11. dcc_mcp_touchdesigner-0.1.0/pyproject.toml +89 -0
  12. dcc_mcp_touchdesigner-0.1.0/release-please-config.json +36 -0
  13. dcc_mcp_touchdesigner-0.1.0/src/dcc_mcp_touchdesigner/__init__.py +48 -0
  14. dcc_mcp_touchdesigner-0.1.0/src/dcc_mcp_touchdesigner/__version__.py +1 -0
  15. dcc_mcp_touchdesigner-0.1.0/src/dcc_mcp_touchdesigner/_core_compat.py +37 -0
  16. dcc_mcp_touchdesigner-0.1.0/src/dcc_mcp_touchdesigner/_env.py +107 -0
  17. dcc_mcp_touchdesigner-0.1.0/src/dcc_mcp_touchdesigner/api.py +26 -0
  18. dcc_mcp_touchdesigner-0.1.0/src/dcc_mcp_touchdesigner/capabilities.py +61 -0
  19. dcc_mcp_touchdesigner-0.1.0/src/dcc_mcp_touchdesigner/dispatcher/__init__.py +17 -0
  20. dcc_mcp_touchdesigner-0.1.0/src/dcc_mcp_touchdesigner/host.py +365 -0
  21. dcc_mcp_touchdesigner-0.1.0/src/dcc_mcp_touchdesigner/operations.py +240 -0
  22. dcc_mcp_touchdesigner-0.1.0/src/dcc_mcp_touchdesigner/server.py +561 -0
  23. dcc_mcp_touchdesigner-0.1.0/src/dcc_mcp_touchdesigner/skills/touchdesigner-scripting/SKILL.md +39 -0
  24. dcc_mcp_touchdesigner-0.1.0/src/dcc_mcp_touchdesigner/skills/touchdesigner-scripting/scripts/capture_top.py +20 -0
  25. dcc_mcp_touchdesigner-0.1.0/src/dcc_mcp_touchdesigner/skills/touchdesigner-scripting/scripts/connect_operators.py +30 -0
  26. dcc_mcp_touchdesigner-0.1.0/src/dcc_mcp_touchdesigner/skills/touchdesigner-scripting/scripts/create_operator.py +20 -0
  27. dcc_mcp_touchdesigner-0.1.0/src/dcc_mcp_touchdesigner/skills/touchdesigner-scripting/scripts/delete_operator.py +20 -0
  28. dcc_mcp_touchdesigner-0.1.0/src/dcc_mcp_touchdesigner/skills/touchdesigner-scripting/scripts/execute_python.py +65 -0
  29. dcc_mcp_touchdesigner-0.1.0/src/dcc_mcp_touchdesigner/skills/touchdesigner-scripting/scripts/get_op_parameters.py +29 -0
  30. dcc_mcp_touchdesigner-0.1.0/src/dcc_mcp_touchdesigner/skills/touchdesigner-scripting/scripts/get_project_info.py +20 -0
  31. dcc_mcp_touchdesigner-0.1.0/src/dcc_mcp_touchdesigner/skills/touchdesigner-scripting/scripts/list_operators.py +33 -0
  32. dcc_mcp_touchdesigner-0.1.0/src/dcc_mcp_touchdesigner/skills/touchdesigner-scripting/scripts/save_project.py +20 -0
  33. dcc_mcp_touchdesigner-0.1.0/src/dcc_mcp_touchdesigner/skills/touchdesigner-scripting/scripts/set_op_parameter.py +28 -0
  34. dcc_mcp_touchdesigner-0.1.0/src/dcc_mcp_touchdesigner/skills/touchdesigner-scripting/tools.yaml +329 -0
  35. dcc_mcp_touchdesigner-0.1.0/tests/test_host.py +73 -0
  36. dcc_mcp_touchdesigner-0.1.0/tests/test_operations.py +177 -0
  37. dcc_mcp_touchdesigner-0.1.0/tests/test_packaging.py +34 -0
  38. dcc_mcp_touchdesigner-0.1.0/tests/test_server.py +502 -0
  39. dcc_mcp_touchdesigner-0.1.0/tests/test_skill_contract.py +44 -0
  40. dcc_mcp_touchdesigner-0.1.0/uv.lock +1541 -0
@@ -0,0 +1,42 @@
1
+ """CI script — start the TouchDesigner MCP server for smoke testing.
2
+
3
+ This script CANNOT run in CI without a running TouchDesigner process.
4
+ It serves as a reference for manual smoke testing.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import json
10
+ import sys
11
+
12
+
13
+ def main() -> int:
14
+ """Start dcc-mcp-touchdesigner and print the MCP URL as JSON."""
15
+ try:
16
+ import dcc_mcp_touchdesigner
17
+ except ImportError:
18
+ print(json.dumps({"error": "dcc_mcp_touchdesigner not installed"}))
19
+ return 1
20
+
21
+ try:
22
+ server = dcc_mcp_touchdesigner.start_server(port=0)
23
+ server.discover_skills()
24
+ print(
25
+ json.dumps(
26
+ {
27
+ "status": "running",
28
+ "mcp_url": server.mcp_url,
29
+ "port": server.port,
30
+ "version": dcc_mcp_touchdesigner.__version__,
31
+ "skills_discovered": server.loaded_skill_count(),
32
+ }
33
+ )
34
+ )
35
+ return 0
36
+ except Exception as exc:
37
+ print(json.dumps({"error": str(exc)}))
38
+ return 1
39
+
40
+
41
+ if __name__ == "__main__":
42
+ sys.exit(main())
@@ -0,0 +1,59 @@
1
+ name: CI
2
+
3
+ on:
4
+ pull_request:
5
+ push:
6
+ branches: [main]
7
+
8
+ permissions:
9
+ contents: read
10
+
11
+ concurrency:
12
+ group: ci-${{ github.workflow }}-${{ github.ref }}
13
+ cancel-in-progress: true
14
+
15
+ jobs:
16
+ test:
17
+ name: Python ${{ matrix.python-version }}
18
+ runs-on: ubuntu-latest
19
+ timeout-minutes: 15
20
+ strategy:
21
+ fail-fast: false
22
+ matrix:
23
+ python-version: ["3.9", "3.12"]
24
+
25
+ steps:
26
+ - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
27
+ - uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6
28
+ with:
29
+ python-version: ${{ matrix.python-version }}
30
+ cache: pip
31
+ - name: Install
32
+ run: python -m pip install -e ".[dev]" build twine
33
+ - name: Install dcc-mcp-cli
34
+ env:
35
+ DCC_MCP_CLI_VERSION: 0.20.2
36
+ DCC_MCP_CLI_SHA256: 1168ebe901cfc0526d3d0f363d18ac4f8e21d2bcc874557e5813acbee8480f9c
37
+ run: |
38
+ curl --fail --location --retry 3 \
39
+ --output /tmp/dcc-mcp-cli \
40
+ "https://github.com/dcc-mcp/dcc-mcp-core/releases/download/v${DCC_MCP_CLI_VERSION}/dcc-mcp-cli-linux-x86_64"
41
+ echo "${DCC_MCP_CLI_SHA256} /tmp/dcc-mcp-cli" | sha256sum --check
42
+ chmod +x /tmp/dcc-mcp-cli
43
+ sudo install /tmp/dcc-mcp-cli /usr/local/bin/dcc-mcp-cli
44
+ - name: Lint
45
+ run: |
46
+ ruff check src tests packaging .github/scripts
47
+ ruff format --check src tests packaging .github/scripts
48
+ - name: Validate packaged Skill
49
+ run: dcc-mcp-cli lint --warnings-as-errors src/dcc_mcp_touchdesigner/skills/touchdesigner-scripting
50
+ - name: Test
51
+ run: pytest
52
+ - name: Build
53
+ if: matrix.python-version == '3.12'
54
+ run: |
55
+ python -m build
56
+ twine check dist/*
57
+ python -m venv wheel-smoke
58
+ wheel-smoke/bin/python -m pip install dist/*.whl
59
+ wheel-smoke/bin/python -c "import importlib.resources as r; root = r.files('dcc_mcp_touchdesigner'); assert root.joinpath('skills', 'touchdesigner-scripting', 'tools.yaml').is_file()"
@@ -0,0 +1,68 @@
1
+ name: Release
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ workflow_dispatch:
7
+ inputs:
8
+ tag_name:
9
+ description: Existing tag to rebuild and publish
10
+ required: false
11
+ default: ""
12
+ publish_to_pypi:
13
+ description: Publish a manually rebuilt tag to PyPI
14
+ type: boolean
15
+ required: false
16
+ default: false
17
+
18
+ concurrency:
19
+ group: ${{ github.workflow }}-${{ github.ref }}
20
+ cancel-in-progress: false
21
+
22
+ permissions:
23
+ contents: read
24
+
25
+ jobs:
26
+ release-please:
27
+ runs-on: ubuntu-latest
28
+ timeout-minutes: 10
29
+ if: github.ref == 'refs/heads/main'
30
+ permissions:
31
+ contents: write
32
+ pull-requests: write
33
+ outputs:
34
+ release_created: ${{ steps.release.outputs.release_created }}
35
+ tag_name: ${{ steps.release.outputs.tag_name || inputs.tag_name }}
36
+ steps:
37
+ - uses: googleapis/release-please-action@0dfd8538845b8e92600d271a895a5372865d4062 # v5
38
+ id: release
39
+ with:
40
+ token: ${{ github.token }}
41
+ config-file: release-please-config.json
42
+ manifest-file: .release-please-manifest.json
43
+
44
+ build-and-publish:
45
+ needs: release-please
46
+ if: needs.release-please.outputs.release_created == 'true' || (github.event_name == 'workflow_dispatch' && inputs.tag_name != '' && inputs.publish_to_pypi)
47
+ runs-on: ubuntu-latest
48
+ timeout-minutes: 15
49
+ environment:
50
+ name: pypi
51
+ url: https://pypi.org/p/dcc-mcp-touchdesigner
52
+ permissions:
53
+ contents: read
54
+ id-token: write
55
+ steps:
56
+ - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
57
+ with:
58
+ ref: ${{ needs.release-please.outputs.tag_name || inputs.tag_name }}
59
+ - uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6
60
+ with:
61
+ python-version: "3.12"
62
+ - run: python -m pip install --upgrade pip build twine
63
+ - run: python -m build
64
+ - run: python -m twine check dist/*
65
+ - uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # release/v1
66
+ with:
67
+ verbose: true
68
+ print-hash: true
@@ -0,0 +1,32 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.egg-info/
5
+ dist/
6
+ build/
7
+ .eggs/
8
+ *.egg
9
+
10
+ # Virtual envs
11
+ venv/
12
+ .venv/
13
+ env/
14
+
15
+ # IDE
16
+ .vscode/
17
+ .idea/
18
+ *.swp
19
+ *.swo
20
+
21
+ # Testing
22
+ .pytest_cache/
23
+ .coverage
24
+ htmlcov/
25
+ .tox/
26
+
27
+ # OS
28
+ .DS_Store
29
+ Thumbs.db
30
+
31
+ # Project
32
+ *.toe.hold
@@ -0,0 +1,3 @@
1
+ {
2
+ ".": "0.1.0"
3
+ }
@@ -0,0 +1,18 @@
1
+ # Changelog
2
+
3
+ ## 0.1.0 (2026-08-12)
4
+
5
+
6
+ ### Features
7
+
8
+ * initial TouchDesigner MCP adapter ([b1df6a7](https://github.com/dcc-mcp/dcc-mcp-touchdesigner/commit/b1df6a70605bc0066ff55a21602de67f662b3d58))
9
+ * ship production-ready TouchDesigner workflows ([#3](https://github.com/dcc-mcp/dcc-mcp-touchdesigner/issues/3)) ([973eef9](https://github.com/dcc-mcp/dcc-mcp-touchdesigner/commit/973eef9b1ee8c6c076b3c66fa4d03771f25cfc04))
10
+
11
+
12
+ ### Bug Fixes
13
+
14
+ * start TouchDesigner UI dispatcher lifecycle ([614f59f](https://github.com/dcc-mcp/dcc-mcp-touchdesigner/commit/614f59fced955f7088a6530755cf55263ced8a05))
15
+
16
+ ## Changelog
17
+
18
+ All notable changes are generated from Conventional Commits by Release Please.
@@ -0,0 +1,129 @@
1
+ Metadata-Version: 2.5
2
+ Name: dcc-mcp-touchdesigner
3
+ Version: 0.1.0
4
+ Summary: TouchDesigner integration for the DCC Model Context Protocol (MCP) ecosystem — embeds a Streamable HTTP MCP server directly inside TouchDesigner
5
+ Project-URL: Homepage, https://github.com/dcc-mcp/dcc-mcp-touchdesigner
6
+ Project-URL: Repository, https://github.com/dcc-mcp/dcc-mcp-touchdesigner
7
+ Project-URL: Issues, https://github.com/dcc-mcp/dcc-mcp-touchdesigner/issues
8
+ Author-email: Long Hao <hal.long@outlook.com>
9
+ License: MIT
10
+ Keywords: ai,dcc,llm,mcp,model-context-protocol,touchdesigner
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.9
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Topic :: Multimedia :: Graphics
20
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
21
+ Requires-Python: >=3.9
22
+ Requires-Dist: dcc-mcp-core<1.0.0,>=0.19.91
23
+ Provides-Extra: dev
24
+ Requires-Dist: build>=1.2; extra == 'dev'
25
+ Requires-Dist: pytest-cov>=4.0; extra == 'dev'
26
+ Requires-Dist: pytest-mock>=3.0; extra == 'dev'
27
+ Requires-Dist: pytest>=8.0; extra == 'dev'
28
+ Requires-Dist: pyyaml>=5.0; extra == 'dev'
29
+ Requires-Dist: ruff>=0.8.0; extra == 'dev'
30
+ Requires-Dist: twine<7.0,>=6.2; (python_version < '3.10') and extra == 'dev'
31
+ Requires-Dist: twine>=7.0; (python_version >= '3.10') and extra == 'dev'
32
+ Description-Content-Type: text/markdown
33
+
34
+ # dcc-mcp-touchdesigner
35
+
36
+ <p align="center">
37
+ <img src="docs/assets/dcc-mcp-touchdesigner.svg" alt="DCC-MCP · TouchDesigner" width="600">
38
+ </p>
39
+
40
+ Typed, main-thread-safe TouchDesigner control for the [DCC Model Context Protocol](https://github.com/dcc-mcp/dcc-mcp-core).
41
+
42
+ The adapter embeds the DCC-MCP HTTP runtime in TouchDesigner, registers the instance with the local gateway, and executes TouchDesigner API work through the documented `td.run()` scheduler. Agents can inspect and edit operator networks, set parameters, save projects, and export TOP images without sending TouchDesigner objects to background threads.
43
+
44
+ ![Typed request flows through a main-thread operator graph into a verified visual, project, and PNG artifact](docs/images/touchdesigner-scripting-showcase.webp)
45
+
46
+ _Illustrative workflow visualization generated with OpenAI ImageGen from the retained source in `docs/images/sources`. It is not a TouchDesigner screenshot or host-validation artifact. The header uses an approved operator-network reference motif rather than an official host mark._
47
+
48
+ ## Install
49
+
50
+ TouchDesigner 2025 uses Python 3.11. Install this package into a matching external environment and expose that environment to TouchDesigner. The preferred TouchDesigner 2025 route is the built-in `TDPyEnvManager`; the Preferences dialog's external Python module path is also supported.
51
+
52
+ ```powershell
53
+ py -3.11 -m venv .venv
54
+ .\.venv\Scripts\python -m pip install --upgrade pip
55
+ .\.venv\Scripts\python -m pip install dcc-mcp-touchdesigner
56
+ ```
57
+
58
+ See [install.md](install.md) for the complete Windows and macOS setup, dependency isolation guidance, and startup configuration. TouchDesigner documents both [external Python packages](https://docs.derivative.ca/Python#Installing_Custom_Python_Packages) and the [TDPyEnvManager](https://docs.derivative.ca/Palette%3AtdPyEnvManager).
59
+
60
+ ## Start in TouchDesigner
61
+
62
+ Run this from the Textport or an Execute DAT `onStart()` callback:
63
+
64
+ ```python
65
+ import dcc_mcp_touchdesigner
66
+
67
+ server = dcc_mcp_touchdesigner.start_server()
68
+ print(server.mcp_url)
69
+ ```
70
+
71
+ `start_server()` is idempotent inside one TouchDesigner process. It loads the bundled skill by default, selects an OS-assigned loopback port, starts the main-thread pump, and advertises the instance to a running DCC-MCP gateway. Stop it explicitly during project teardown when needed:
72
+
73
+ ```python
74
+ dcc_mcp_touchdesigner.stop_server()
75
+ ```
76
+
77
+ ## Typed tools
78
+
79
+ | Tool | Contract | Risk |
80
+ | --- | --- | --- |
81
+ | `get_project_info` | Read project name, folder, build, cook rate, and root count | Read-only |
82
+ | `list_operators` | List direct or recursive operators with an optional family/type filter | Read-only |
83
+ | `get_op_parameters` | Read selected or all parameters from one operator | Read-only |
84
+ | `create_operator` | Create a documented operator type under an explicit COMP | Mutation |
85
+ | `connect_operators` | Connect an explicit output connector to an explicit input | Mutation |
86
+ | `set_op_parameter` | Set one parameter and return its evaluated value | Idempotent mutation |
87
+ | `capture_top` | Save one TOP to an explicit PNG path with size and SHA-256 metadata | File write |
88
+ | `save_project` | Save the current project to an explicit `.toe` path | File write |
89
+ | `delete_operator` | Delete one explicitly addressed non-root operator | Destructive |
90
+ | `execute_python` | Advanced in-host Python escape hatch; disabled by policy when required | Destructive |
91
+
92
+ Every tool has a JSON input/output contract and is dispatched on TouchDesigner's main thread. File-writing tools require an explicit path and reject accidental overwrite unless `overwrite=true` is supplied. Root deletion is always rejected.
93
+
94
+ ## Security controls
95
+
96
+ Disable arbitrary Python execution in controlled environments before starting TouchDesigner:
97
+
98
+ ```powershell
99
+ $env:DCC_MCP_TOUCHDESIGNER_DISABLE_EXECUTE_PYTHON = "1"
100
+ ```
101
+
102
+ The adapter binds to loopback by default. Do not expose the per-instance port directly to an untrusted network. Use the DCC-MCP gateway when multiple instances or attributable agent sessions are required.
103
+
104
+ ## Runtime configuration
105
+
106
+ | Variable | Purpose |
107
+ | --- | --- |
108
+ | `DCC_MCP_TOUCHDESIGNER_SKILL_PATHS` | Additional skill directories |
109
+ | `DCC_MCP_TOUCHDESIGNER_METRICS` | Enable Prometheus `/metrics` |
110
+ | `DCC_MCP_TOUCHDESIGNER_ENABLE_GATEWAY_FAILOVER` | Enable gateway failover; on by default |
111
+ | `DCC_MCP_TOUCHDESIGNER_DISABLE_EXECUTE_PYTHON` | Disable the advanced Python tool |
112
+
113
+ ## Development
114
+
115
+ ```powershell
116
+ py -3.11 -m pip install -e ".[dev]"
117
+ pytest
118
+ ruff check .
119
+ ruff format --check .
120
+ dcc-mcp-cli lint src/dcc_mcp_touchdesigner/skills/touchdesigner-scripting --warnings-as-errors
121
+ python -m build
122
+ python -m twine check dist/*
123
+ ```
124
+
125
+ Unit and contract tests use a deterministic TouchDesigner API double. A release additionally requires a real TouchDesigner process, six readiness checks, discovery of all ten typed tools, and a create/connect/set/capture/save/delete chain through `dcc-mcp-cli`; simulation alone is not release evidence.
126
+
127
+ ## License
128
+
129
+ MIT
@@ -0,0 +1,96 @@
1
+ # dcc-mcp-touchdesigner
2
+
3
+ <p align="center">
4
+ <img src="docs/assets/dcc-mcp-touchdesigner.svg" alt="DCC-MCP · TouchDesigner" width="600">
5
+ </p>
6
+
7
+ Typed, main-thread-safe TouchDesigner control for the [DCC Model Context Protocol](https://github.com/dcc-mcp/dcc-mcp-core).
8
+
9
+ The adapter embeds the DCC-MCP HTTP runtime in TouchDesigner, registers the instance with the local gateway, and executes TouchDesigner API work through the documented `td.run()` scheduler. Agents can inspect and edit operator networks, set parameters, save projects, and export TOP images without sending TouchDesigner objects to background threads.
10
+
11
+ ![Typed request flows through a main-thread operator graph into a verified visual, project, and PNG artifact](docs/images/touchdesigner-scripting-showcase.webp)
12
+
13
+ _Illustrative workflow visualization generated with OpenAI ImageGen from the retained source in `docs/images/sources`. It is not a TouchDesigner screenshot or host-validation artifact. The header uses an approved operator-network reference motif rather than an official host mark._
14
+
15
+ ## Install
16
+
17
+ TouchDesigner 2025 uses Python 3.11. Install this package into a matching external environment and expose that environment to TouchDesigner. The preferred TouchDesigner 2025 route is the built-in `TDPyEnvManager`; the Preferences dialog's external Python module path is also supported.
18
+
19
+ ```powershell
20
+ py -3.11 -m venv .venv
21
+ .\.venv\Scripts\python -m pip install --upgrade pip
22
+ .\.venv\Scripts\python -m pip install dcc-mcp-touchdesigner
23
+ ```
24
+
25
+ See [install.md](install.md) for the complete Windows and macOS setup, dependency isolation guidance, and startup configuration. TouchDesigner documents both [external Python packages](https://docs.derivative.ca/Python#Installing_Custom_Python_Packages) and the [TDPyEnvManager](https://docs.derivative.ca/Palette%3AtdPyEnvManager).
26
+
27
+ ## Start in TouchDesigner
28
+
29
+ Run this from the Textport or an Execute DAT `onStart()` callback:
30
+
31
+ ```python
32
+ import dcc_mcp_touchdesigner
33
+
34
+ server = dcc_mcp_touchdesigner.start_server()
35
+ print(server.mcp_url)
36
+ ```
37
+
38
+ `start_server()` is idempotent inside one TouchDesigner process. It loads the bundled skill by default, selects an OS-assigned loopback port, starts the main-thread pump, and advertises the instance to a running DCC-MCP gateway. Stop it explicitly during project teardown when needed:
39
+
40
+ ```python
41
+ dcc_mcp_touchdesigner.stop_server()
42
+ ```
43
+
44
+ ## Typed tools
45
+
46
+ | Tool | Contract | Risk |
47
+ | --- | --- | --- |
48
+ | `get_project_info` | Read project name, folder, build, cook rate, and root count | Read-only |
49
+ | `list_operators` | List direct or recursive operators with an optional family/type filter | Read-only |
50
+ | `get_op_parameters` | Read selected or all parameters from one operator | Read-only |
51
+ | `create_operator` | Create a documented operator type under an explicit COMP | Mutation |
52
+ | `connect_operators` | Connect an explicit output connector to an explicit input | Mutation |
53
+ | `set_op_parameter` | Set one parameter and return its evaluated value | Idempotent mutation |
54
+ | `capture_top` | Save one TOP to an explicit PNG path with size and SHA-256 metadata | File write |
55
+ | `save_project` | Save the current project to an explicit `.toe` path | File write |
56
+ | `delete_operator` | Delete one explicitly addressed non-root operator | Destructive |
57
+ | `execute_python` | Advanced in-host Python escape hatch; disabled by policy when required | Destructive |
58
+
59
+ Every tool has a JSON input/output contract and is dispatched on TouchDesigner's main thread. File-writing tools require an explicit path and reject accidental overwrite unless `overwrite=true` is supplied. Root deletion is always rejected.
60
+
61
+ ## Security controls
62
+
63
+ Disable arbitrary Python execution in controlled environments before starting TouchDesigner:
64
+
65
+ ```powershell
66
+ $env:DCC_MCP_TOUCHDESIGNER_DISABLE_EXECUTE_PYTHON = "1"
67
+ ```
68
+
69
+ The adapter binds to loopback by default. Do not expose the per-instance port directly to an untrusted network. Use the DCC-MCP gateway when multiple instances or attributable agent sessions are required.
70
+
71
+ ## Runtime configuration
72
+
73
+ | Variable | Purpose |
74
+ | --- | --- |
75
+ | `DCC_MCP_TOUCHDESIGNER_SKILL_PATHS` | Additional skill directories |
76
+ | `DCC_MCP_TOUCHDESIGNER_METRICS` | Enable Prometheus `/metrics` |
77
+ | `DCC_MCP_TOUCHDESIGNER_ENABLE_GATEWAY_FAILOVER` | Enable gateway failover; on by default |
78
+ | `DCC_MCP_TOUCHDESIGNER_DISABLE_EXECUTE_PYTHON` | Disable the advanced Python tool |
79
+
80
+ ## Development
81
+
82
+ ```powershell
83
+ py -3.11 -m pip install -e ".[dev]"
84
+ pytest
85
+ ruff check .
86
+ ruff format --check .
87
+ dcc-mcp-cli lint src/dcc_mcp_touchdesigner/skills/touchdesigner-scripting --warnings-as-errors
88
+ python -m build
89
+ python -m twine check dist/*
90
+ ```
91
+
92
+ Unit and contract tests use a deterministic TouchDesigner API double. A release additionally requires a real TouchDesigner process, six readiness checks, discovery of all ten typed tools, and a create/connect/set/capture/save/delete chain through `dcc-mcp-cli`; simulation alone is not release evidence.
93
+
94
+ ## License
95
+
96
+ MIT
@@ -0,0 +1,123 @@
1
+ # Installing dcc-mcp-touchdesigner
2
+
3
+ ## Requirements
4
+
5
+ - TouchDesigner 2025 official build
6
+ - A Python environment matching TouchDesigner's embedded Python version
7
+ - `dcc-mcp-touchdesigner` and its `dcc-mcp-core` dependency installed into that environment
8
+
9
+ TouchDesigner 2025 currently embeds Python 3.11. Confirm the exact interpreter from the Textport before creating an environment:
10
+
11
+ ```python
12
+ app.pythonExecutable
13
+ import sys
14
+
15
+ sys.version
16
+ ```
17
+
18
+ Do not mix an environment built for a different Python minor version. Avoid overriding TouchDesigner's bundled NumPy or OpenCV unless the project explicitly owns and tests those versions.
19
+
20
+ ## Preferred: TDPyEnvManager
21
+
22
+ TouchDesigner 2025 includes `TDPyEnvManager` in the Palette. It creates a project-local Python environment, adds it to TouchDesigner's import path, and can restore requirements at startup.
23
+
24
+ 1. Add `TDPyEnvManager` from the Palette to the project.
25
+ 2. Select Python vEnv mode and create a `.venv` beside the `.toe` project.
26
+ 3. Open that environment's CLI from the component.
27
+ 4. Install the adapter:
28
+
29
+ ```text
30
+ python -m pip install --upgrade pip
31
+ python -m pip install dcc-mcp-touchdesigner
32
+ ```
33
+
34
+ 5. Restart TouchDesigner so its Python search path is rebuilt.
35
+
36
+ For a reproducible project, add this line to the project's `requirements.txt` and let the component restore it:
37
+
38
+ ```text
39
+ dcc-mcp-touchdesigner==0.1.0
40
+ ```
41
+
42
+ See Derivative's [TDPyEnvManager documentation](https://docs.derivative.ca/Palette%3AtdPyEnvManager) for `pyproject.toml`, `autoSetup`, and environment lifecycle options.
43
+
44
+ ## Alternative: external Python 3.11 environment
45
+
46
+ Create a normal Python 3.11 virtual environment outside TouchDesigner:
47
+
48
+ ```powershell
49
+ py -3.11 -m venv .venv
50
+ .\.venv\Scripts\python -m pip install --upgrade pip
51
+ .\.venv\Scripts\python -m pip install dcc-mcp-touchdesigner
52
+ ```
53
+
54
+ In TouchDesigner, open **Edit > Preferences > Python**:
55
+
56
+ 1. Enable **Add Externally Installed Python Site-Packages to Search Path**.
57
+ 2. Set **Python 64-bit Module Path** to the environment's `Lib\site-packages` directory on Windows, or `lib/python3.11/site-packages` on macOS.
58
+ 3. Restart TouchDesigner.
59
+
60
+ Derivative documents this path in [Installing Custom Python Packages](https://docs.derivative.ca/Python#Installing_Custom_Python_Packages).
61
+
62
+ ## Verify imports
63
+
64
+ Open the Textport and run:
65
+
66
+ ```python
67
+ import dcc_mcp_core
68
+ import dcc_mcp_touchdesigner
69
+
70
+ print(dcc_mcp_touchdesigner.__version__)
71
+ ```
72
+
73
+ The `td` module is only available inside TouchDesigner. A normal terminal can validate package installation, but it cannot validate host dispatch or typed tool execution.
74
+
75
+ ## Start and stop with the project
76
+
77
+ For manual testing:
78
+
79
+ ```python
80
+ import dcc_mcp_touchdesigner
81
+
82
+ server = dcc_mcp_touchdesigner.start_server()
83
+ print(server.mcp_url)
84
+ ```
85
+
86
+ For persistent startup, place the same call in an Execute DAT `onStart()` callback. Pair it with `stop_server()` in `onExit()`:
87
+
88
+ ```python
89
+ def onStart():
90
+ import dcc_mcp_touchdesigner
91
+
92
+ dcc_mcp_touchdesigner.start_server()
93
+ return
94
+
95
+
96
+ def onExit():
97
+ import dcc_mcp_touchdesigner
98
+
99
+ dcc_mcp_touchdesigner.stop_server()
100
+ return
101
+ ```
102
+
103
+ The server uses an OS-assigned loopback port and registers itself when a DCC-MCP gateway is available. Do not hard-code a port unless an isolated integration requires it.
104
+
105
+ ## Verify readiness and tools
106
+
107
+ From a terminal with `dcc-mcp-cli` installed:
108
+
109
+ ```powershell
110
+ dcc-mcp-cli list --output json
111
+ dcc-mcp-cli search --dcc-type touchdesigner --output json
112
+ ```
113
+
114
+ For release acceptance, verify all six readiness checks and call a cheap read-only typed tool before any mutation. Route later calls to the exact `instance_id` when more than one TouchDesigner process is running.
115
+
116
+ ## Troubleshooting
117
+
118
+ - `No module named dcc_mcp_touchdesigner`: confirm the configured site-packages path and restart TouchDesigner.
119
+ - Binary import or DLL load errors: rebuild the environment with the exact Python minor version reported by `sys.version`.
120
+ - `No module named td` in a terminal: expected; run host API code inside TouchDesigner.
121
+ - Instance absent from the CLI: compare the registry directory and gateway environment used by TouchDesigner and the terminal.
122
+ - HTTP server is available but host tools time out: confirm the project is cooking and the adapter's `td.run()` main-thread pump has not been stopped.
123
+ - `execute_python` is unavailable: check `DCC_MCP_TOUCHDESIGNER_DISABLE_EXECUTE_PYTHON`; typed tools remain available.
@@ -0,0 +1,69 @@
1
+ """Assemble dcc-mcp-touchdesigner release payload.
2
+
3
+ Usage: python packaging/assemble_release.py
4
+
5
+ Produces a zip archive with the wheel plus a bootstrap script that can be
6
+ extracted into TouchDesigner's site-packages or a custom project folder.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ import argparse
12
+ import subprocess
13
+ import sys
14
+ from pathlib import Path
15
+ from zipfile import ZIP_DEFLATED, ZipFile
16
+
17
+ ROOT = Path(__file__).resolve().parent.parent
18
+ DIST = ROOT / "dist"
19
+ BOOTSTRAP_TEMPLATE = '''"""TouchDesigner MCP bootstrap — run from a Text DAT on the host thread."""
20
+ import os
21
+ import sys
22
+
23
+ _WHEEL = os.path.join(os.path.dirname(__file__), "payload", {wheel_name!r})
24
+ if not os.path.isfile(_WHEEL):
25
+ raise RuntimeError(f"TouchDesigner adapter wheel not found: {{_WHEEL}}")
26
+ if _WHEEL not in sys.path:
27
+ sys.path.insert(0, _WHEEL)
28
+
29
+ import dcc_mcp_touchdesigner
30
+
31
+ server = dcc_mcp_touchdesigner.start_server()
32
+ print(f"[dcc-mcp-touchdesigner] MCP server listening at {{server.mcp_url}}")
33
+ '''
34
+
35
+
36
+ def build_wheel() -> Path:
37
+ """Build the Python wheel and return its path."""
38
+ subprocess.run(
39
+ [sys.executable, "-m", "pip", "wheel", "--no-deps", "-w", str(DIST), str(ROOT)],
40
+ check=True,
41
+ )
42
+ wheels = sorted(DIST.glob("dcc_mcp_touchdesigner-*.whl"))
43
+ if not wheels:
44
+ raise SystemExit("wheel build failed: no .whl found")
45
+ return wheels[-1]
46
+
47
+
48
+ def assemble_zip(out_path: Path, wheel: Path) -> None:
49
+ """Create the release zip with bootstrap script + wheel."""
50
+ with ZipFile(out_path, "w", ZIP_DEFLATED) as zf:
51
+ zf.writestr("bootstrap.py", BOOTSTRAP_TEMPLATE.format(wheel_name=wheel.name))
52
+ zf.write(wheel, f"payload/{wheel.name}")
53
+ print(f"Release zip written to: {out_path}")
54
+
55
+
56
+ def main() -> None:
57
+ parser = argparse.ArgumentParser(description="Assemble dcc-mcp-touchdesigner release")
58
+ parser.add_argument("-o", "--output", default=None, help="Output zip path")
59
+ args = parser.parse_args()
60
+
61
+ DIST.mkdir(exist_ok=True)
62
+ wheel = build_wheel()
63
+ out = args.output or str(DIST / "dcc-mcp-touchdesigner-release.zip")
64
+ assemble_zip(Path(out), wheel)
65
+ print("Done.")
66
+
67
+
68
+ if __name__ == "__main__":
69
+ main()