dcc-mcp-sketchup 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.
- dcc_mcp_sketchup-0.1.0/.github/workflows/ci.yml +75 -0
- dcc_mcp_sketchup-0.1.0/.github/workflows/release.yml +68 -0
- dcc_mcp_sketchup-0.1.0/.gitignore +8 -0
- dcc_mcp_sketchup-0.1.0/.release-please-manifest.json +3 -0
- dcc_mcp_sketchup-0.1.0/CHANGELOG.md +13 -0
- dcc_mcp_sketchup-0.1.0/LICENSE +22 -0
- dcc_mcp_sketchup-0.1.0/PKG-INFO +179 -0
- dcc_mcp_sketchup-0.1.0/README.md +145 -0
- dcc_mcp_sketchup-0.1.0/docs/architecture.md +54 -0
- dcc_mcp_sketchup-0.1.0/pyproject.toml +58 -0
- dcc_mcp_sketchup-0.1.0/release-please-config.json +19 -0
- dcc_mcp_sketchup-0.1.0/src/dcc_mcp_sketchup/__init__.py +4 -0
- dcc_mcp_sketchup-0.1.0/src/dcc_mcp_sketchup/__version__.py +1 -0
- dcc_mcp_sketchup-0.1.0/src/dcc_mcp_sketchup/bridge.py +181 -0
- dcc_mcp_sketchup-0.1.0/src/dcc_mcp_sketchup/dispatcher.py +22 -0
- dcc_mcp_sketchup-0.1.0/src/dcc_mcp_sketchup/install.py +119 -0
- dcc_mcp_sketchup-0.1.0/src/dcc_mcp_sketchup/server.py +246 -0
- dcc_mcp_sketchup-0.1.0/src/dcc_mcp_sketchup/sketchup_plugin/commands.rb +808 -0
- dcc_mcp_sketchup-0.1.0/src/dcc_mcp_sketchup/sketchup_plugin/main.rb +25 -0
- dcc_mcp_sketchup-0.1.0/src/dcc_mcp_sketchup/sketchup_plugin/registration.rb +18 -0
- dcc_mcp_sketchup-0.1.0/src/dcc_mcp_sketchup/sketchup_plugin/runtime.rb +504 -0
- dcc_mcp_sketchup-0.1.0/src/dcc_mcp_sketchup/skill_tools.py +22 -0
- dcc_mcp_sketchup-0.1.0/src/dcc_mcp_sketchup/skills/sketchup-materials/SKILL.md +24 -0
- dcc_mcp_sketchup-0.1.0/src/dcc_mcp_sketchup/skills/sketchup-materials/scripts/assign_material.py +8 -0
- dcc_mcp_sketchup-0.1.0/src/dcc_mcp_sketchup/skills/sketchup-materials/scripts/create_material.py +8 -0
- dcc_mcp_sketchup-0.1.0/src/dcc_mcp_sketchup/skills/sketchup-materials/scripts/list_materials.py +8 -0
- dcc_mcp_sketchup-0.1.0/src/dcc_mcp_sketchup/skills/sketchup-materials/scripts/remove_material.py +8 -0
- dcc_mcp_sketchup-0.1.0/src/dcc_mcp_sketchup/skills/sketchup-materials/scripts/update_material.py +8 -0
- dcc_mcp_sketchup-0.1.0/src/dcc_mcp_sketchup/skills/sketchup-materials/tools.yaml +95 -0
- dcc_mcp_sketchup-0.1.0/src/dcc_mcp_sketchup/skills/sketchup-modeling/SKILL.md +25 -0
- dcc_mcp_sketchup-0.1.0/src/dcc_mcp_sketchup/skills/sketchup-modeling/scripts/add_box.py +8 -0
- dcc_mcp_sketchup-0.1.0/src/dcc_mcp_sketchup/skills/sketchup-modeling/scripts/add_cylinder.py +8 -0
- dcc_mcp_sketchup-0.1.0/src/dcc_mcp_sketchup/skills/sketchup-modeling/scripts/erase_entities.py +8 -0
- dcc_mcp_sketchup-0.1.0/src/dcc_mcp_sketchup/skills/sketchup-modeling/scripts/group_entities.py +8 -0
- dcc_mcp_sketchup-0.1.0/src/dcc_mcp_sketchup/skills/sketchup-modeling/scripts/rename_entity.py +8 -0
- dcc_mcp_sketchup-0.1.0/src/dcc_mcp_sketchup/skills/sketchup-modeling/scripts/select_entities.py +8 -0
- dcc_mcp_sketchup-0.1.0/src/dcc_mcp_sketchup/skills/sketchup-modeling/scripts/transform_entity.py +8 -0
- dcc_mcp_sketchup-0.1.0/src/dcc_mcp_sketchup/skills/sketchup-modeling/tools.yaml +176 -0
- dcc_mcp_sketchup-0.1.0/src/dcc_mcp_sketchup/skills/sketchup-scenes/SKILL.md +24 -0
- dcc_mcp_sketchup-0.1.0/src/dcc_mcp_sketchup/skills/sketchup-scenes/scripts/assign_tag.py +8 -0
- dcc_mcp_sketchup-0.1.0/src/dcc_mcp_sketchup/skills/sketchup-scenes/scripts/create_scene.py +8 -0
- dcc_mcp_sketchup-0.1.0/src/dcc_mcp_sketchup/skills/sketchup-scenes/scripts/create_tag.py +8 -0
- dcc_mcp_sketchup-0.1.0/src/dcc_mcp_sketchup/skills/sketchup-scenes/scripts/list_scenes.py +8 -0
- dcc_mcp_sketchup-0.1.0/src/dcc_mcp_sketchup/skills/sketchup-scenes/scripts/list_tags.py +8 -0
- dcc_mcp_sketchup-0.1.0/src/dcc_mcp_sketchup/skills/sketchup-scenes/scripts/remove_scene.py +8 -0
- dcc_mcp_sketchup-0.1.0/src/dcc_mcp_sketchup/skills/sketchup-scenes/scripts/remove_tag.py +8 -0
- dcc_mcp_sketchup-0.1.0/src/dcc_mcp_sketchup/skills/sketchup-scenes/scripts/update_scene.py +8 -0
- dcc_mcp_sketchup-0.1.0/src/dcc_mcp_sketchup/skills/sketchup-scenes/tools.yaml +124 -0
- dcc_mcp_sketchup-0.1.0/src/dcc_mcp_sketchup/skills/sketchup-session/SKILL.md +25 -0
- dcc_mcp_sketchup-0.1.0/src/dcc_mcp_sketchup/skills/sketchup-session/scripts/export_model.py +8 -0
- dcc_mcp_sketchup-0.1.0/src/dcc_mcp_sketchup/skills/sketchup-session/scripts/get_status.py +8 -0
- dcc_mcp_sketchup-0.1.0/src/dcc_mcp_sketchup/skills/sketchup-session/scripts/import_model.py +8 -0
- dcc_mcp_sketchup-0.1.0/src/dcc_mcp_sketchup/skills/sketchup-session/scripts/inspect_model.py +8 -0
- dcc_mcp_sketchup-0.1.0/src/dcc_mcp_sketchup/skills/sketchup-session/scripts/list_entities.py +8 -0
- dcc_mcp_sketchup-0.1.0/src/dcc_mcp_sketchup/skills/sketchup-session/scripts/save_copy.py +8 -0
- dcc_mcp_sketchup-0.1.0/src/dcc_mcp_sketchup/skills/sketchup-session/scripts/save_model.py +8 -0
- dcc_mcp_sketchup-0.1.0/src/dcc_mcp_sketchup/skills/sketchup-session/scripts/validate_model.py +8 -0
- dcc_mcp_sketchup-0.1.0/src/dcc_mcp_sketchup/skills/sketchup-session/tools.yaml +134 -0
- dcc_mcp_sketchup-0.1.0/tests/ruby/test_commands.rb +372 -0
- dcc_mcp_sketchup-0.1.0/tests/ruby/test_runtime.rb +446 -0
- dcc_mcp_sketchup-0.1.0/tests/test_bridge.py +112 -0
- dcc_mcp_sketchup-0.1.0/tests/test_install.py +66 -0
- dcc_mcp_sketchup-0.1.0/tests/test_python_compat.py +16 -0
- dcc_mcp_sketchup-0.1.0/tests/test_server.py +42 -0
- dcc_mcp_sketchup-0.1.0/tests/test_skills.py +63 -0
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_dispatch:
|
|
5
|
+
push:
|
|
6
|
+
branches: [main, "release-please--branches--**"]
|
|
7
|
+
pull_request:
|
|
8
|
+
branches: [main]
|
|
9
|
+
|
|
10
|
+
concurrency:
|
|
11
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
12
|
+
cancel-in-progress: true
|
|
13
|
+
|
|
14
|
+
permissions:
|
|
15
|
+
contents: read
|
|
16
|
+
|
|
17
|
+
jobs:
|
|
18
|
+
test:
|
|
19
|
+
name: Test Python ${{ matrix.python }} on ${{ matrix.os }}
|
|
20
|
+
runs-on: ${{ matrix.os }}
|
|
21
|
+
timeout-minutes: 15
|
|
22
|
+
strategy:
|
|
23
|
+
fail-fast: false
|
|
24
|
+
matrix:
|
|
25
|
+
os: [ubuntu-latest, windows-latest, macos-latest]
|
|
26
|
+
python: ["3.9", "3.10", "3.11", "3.12"]
|
|
27
|
+
steps:
|
|
28
|
+
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
|
|
29
|
+
- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6
|
|
30
|
+
with:
|
|
31
|
+
python-version: ${{ matrix.python }}
|
|
32
|
+
- run: python -m pip install --upgrade pip
|
|
33
|
+
- run: python -m pip install -e ".[test]"
|
|
34
|
+
- run: python -m pytest
|
|
35
|
+
|
|
36
|
+
ruby-extension:
|
|
37
|
+
name: Ruby ${{ matrix.ruby }} extension contract on ${{ matrix.os }}
|
|
38
|
+
runs-on: ${{ matrix.os }}
|
|
39
|
+
timeout-minutes: 10
|
|
40
|
+
strategy:
|
|
41
|
+
fail-fast: false
|
|
42
|
+
matrix:
|
|
43
|
+
os: [ubuntu-latest, windows-latest]
|
|
44
|
+
ruby: ["2.7", "3.2"]
|
|
45
|
+
steps:
|
|
46
|
+
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
|
|
47
|
+
- uses: ruby/setup-ruby@95ef2b042f9d7a56d8268cba8559e2842e2ad01b # v1
|
|
48
|
+
with:
|
|
49
|
+
ruby-version: ${{ matrix.ruby }}
|
|
50
|
+
- name: Check Ruby syntax
|
|
51
|
+
run: >-
|
|
52
|
+
ruby -e 'Dir["{src/dcc_mcp_sketchup/sketchup_plugin,tests/ruby}/**/*.rb"].sort.each { |file| abort("syntax failed: #{file}") unless system(RbConfig.ruby, "-c", file) }'
|
|
53
|
+
- name: Run Ruby contract tests
|
|
54
|
+
run: ruby -e 'Dir["tests/ruby/test_*.rb"].sort.each { |file| require File.expand_path(file) }'
|
|
55
|
+
|
|
56
|
+
lint-and-build:
|
|
57
|
+
runs-on: ubuntu-latest
|
|
58
|
+
timeout-minutes: 15
|
|
59
|
+
steps:
|
|
60
|
+
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
|
|
61
|
+
- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6
|
|
62
|
+
with:
|
|
63
|
+
python-version: "3.11"
|
|
64
|
+
- run: python -m pip install --upgrade pip
|
|
65
|
+
- run: python -m pip install -e ".[dev]"
|
|
66
|
+
- run: python -m ruff check src tests
|
|
67
|
+
- run: python -m ruff format --check src tests
|
|
68
|
+
- run: python -m build
|
|
69
|
+
- run: python -m twine check dist/*
|
|
70
|
+
- name: Smoke test the built wheel
|
|
71
|
+
shell: bash
|
|
72
|
+
run: |
|
|
73
|
+
python -m pip install --force-reinstall --no-deps dist/*.whl
|
|
74
|
+
python -c "import importlib.metadata as m, importlib.resources as r, dcc_mcp_sketchup as p; assert p.__version__ == m.version('dcc-mcp-sketchup'); root = r.files('dcc_mcp_sketchup'); assert root.joinpath('sketchup_plugin', 'runtime.rb').is_file(); assert root.joinpath('skills', 'sketchup-session', 'SKILL.md').is_file()"
|
|
75
|
+
python -c "import importlib.metadata as m, subprocess; expected = m.version('dcc-mcp-sketchup'); actual = subprocess.check_output(['dcc-mcp-sketchup', '--version'], text=True).strip(); assert actual == expected, (actual, expected)"
|
|
@@ -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-sketchup
|
|
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.11"
|
|
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,13 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.1.0 (2026-08-12)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* add experimental SketchUp adapter ([29a4ee5](https://github.com/dcc-mcp/dcc-mcp-sketchup/commit/29a4ee5178263c84914d17a659f81a3f91d614a6))
|
|
9
|
+
* ship production-ready SketchUp adapter ([#1](https://github.com/dcc-mcp/dcc-mcp-sketchup/issues/1)) ([1cc2fcc](https://github.com/dcc-mcp/dcc-mcp-sketchup/commit/1cc2fcc1b28f5531f3fe344e86c20ab414300b73))
|
|
10
|
+
|
|
11
|
+
## Changelog
|
|
12
|
+
|
|
13
|
+
All notable changes to this project will be documented in this file by Release Please.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 loonghao
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: dcc-mcp-sketchup
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Production SketchUp adapter with an authenticated Ruby main-thread bridge for DCC-MCP
|
|
5
|
+
Project-URL: Homepage, https://github.com/dcc-mcp/dcc-mcp-sketchup
|
|
6
|
+
Project-URL: Repository, https://github.com/dcc-mcp/dcc-mcp-sketchup
|
|
7
|
+
Project-URL: Issues, https://github.com/dcc-mcp/dcc-mcp-sketchup/issues
|
|
8
|
+
Author-email: loonghao <hal.long@outlook.com>
|
|
9
|
+
License: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: 3d-modeling,automation,cad,dcc,mcp,sketchup
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Operating System :: MacOS
|
|
15
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
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>=8; extra == 'dev'
|
|
26
|
+
Requires-Dist: pyyaml>=6; extra == 'dev'
|
|
27
|
+
Requires-Dist: ruff>=0.8; extra == 'dev'
|
|
28
|
+
Requires-Dist: twine>=6; extra == 'dev'
|
|
29
|
+
Provides-Extra: test
|
|
30
|
+
Requires-Dist: pytest>=8; extra == 'test'
|
|
31
|
+
Requires-Dist: pyyaml>=6; extra == 'test'
|
|
32
|
+
Requires-Dist: ruff>=0.8; extra == 'test'
|
|
33
|
+
Description-Content-Type: text/markdown
|
|
34
|
+
|
|
35
|
+
# dcc-mcp-sketchup
|
|
36
|
+
|
|
37
|
+
<p align="center">
|
|
38
|
+
<picture>
|
|
39
|
+
<source media="(prefers-color-scheme: dark)" srcset="docs/assets/dcc-mcp-sketchup-dark.svg">
|
|
40
|
+
<source media="(prefers-color-scheme: light)" srcset="docs/assets/dcc-mcp-sketchup.svg">
|
|
41
|
+
<img src="docs/assets/dcc-mcp-sketchup.svg" alt="DCC-MCP · SKETCHUP" width="600">
|
|
42
|
+
</picture>
|
|
43
|
+
</p>
|
|
44
|
+
|
|
45
|
+
Production SketchUp adapter for the [DCC-MCP](https://github.com/dcc-mcp) ecosystem.
|
|
46
|
+
It combines a small Ruby extension inside SketchUp with an external Python
|
|
47
|
+
sidecar, exposing 28 typed tools without arbitrary Ruby execution.
|
|
48
|
+
|
|
49
|
+

|
|
50
|
+
|
|
51
|
+
<sub>Workflow illustration generated with OpenAI image generation; no third-party source assets.</sub>
|
|
52
|
+
|
|
53
|
+
## Capabilities
|
|
54
|
+
|
|
55
|
+
- Inspect model identity, bounds, entities, selection, and validation state.
|
|
56
|
+
- Save or copy `.skp` models and use installed SketchUp importers/exporters.
|
|
57
|
+
- Create boxes and cylinders, group, transform, rename, select, and erase entities.
|
|
58
|
+
- List, create, edit, assign, and safely remove materials.
|
|
59
|
+
- Manage saved scenes and Tags.
|
|
60
|
+
- Reference entities through SketchUp persistent IDs.
|
|
61
|
+
- Package four discoverable DCC-MCP Skills with complete JSON Schemas and MCP annotations.
|
|
62
|
+
|
|
63
|
+
## Architecture
|
|
64
|
+
|
|
65
|
+
```text
|
|
66
|
+
DCC-MCP client
|
|
67
|
+
|
|
|
68
|
+
v
|
|
69
|
+
external Python sidecar (dcc-mcp-core)
|
|
70
|
+
|
|
|
71
|
+
| authenticated, bounded JSON-RPC on 127.0.0.1
|
|
72
|
+
v
|
|
73
|
+
UI.start_timer callback on SketchUp's UI thread
|
|
74
|
+
|
|
|
75
|
+
| nonblocking, bounded socket pump + one-request queue
|
|
76
|
+
|
|
|
77
|
+
v
|
|
78
|
+
typed SketchUp Ruby API command map
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
The Ruby extension has a single socket owner: the repeating UI timer. Each tick
|
|
82
|
+
uses zero-timeout `IO.select` and nonblocking accept, read, and write operations
|
|
83
|
+
across at most 16 connections, then executes at most one validated request.
|
|
84
|
+
Frame, response, connection, and deadline limits keep every tick bounded while
|
|
85
|
+
preserving SketchUp's thread affinity. No worker thread performs socket I/O or
|
|
86
|
+
calls the SketchUp API. Every model mutation is a named undoable operation.
|
|
87
|
+
|
|
88
|
+
## Requirements
|
|
89
|
+
|
|
90
|
+
- SketchUp Desktop 2021 or newer on Windows or macOS.
|
|
91
|
+
- Python 3.9 or newer for the external sidecar.
|
|
92
|
+
- `dcc-mcp-core>=0.19.91,<1.0.0` (installed automatically).
|
|
93
|
+
|
|
94
|
+
Importer and exporter availability varies by SketchUp edition, version, and
|
|
95
|
+
installed extensions. The adapter reports the host error instead of claiming a
|
|
96
|
+
format is available when SketchUp rejects it.
|
|
97
|
+
|
|
98
|
+
## Install
|
|
99
|
+
|
|
100
|
+
Install the package into the Python environment used by DCC-MCP:
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
python -m pip install dcc-mcp-sketchup
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Start SketchUp once so its versioned user profile exists, then install the Ruby
|
|
107
|
+
extension:
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
dcc-mcp-sketchup install
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
For a specific SketchUp profile, pass its Plugins directory explicitly:
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
dcc-mcp-sketchup install \
|
|
117
|
+
--plugins-dir "C:/Users/you/AppData/Roaming/SketchUp/SketchUp 2026/SketchUp/Plugins"
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Restart SketchUp. The extension binds an ephemeral loopback port, generates a
|
|
121
|
+
random token, and launches the host-bound sidecar automatically. It terminates
|
|
122
|
+
the sidecar when SketchUp exits.
|
|
123
|
+
|
|
124
|
+
To update or remove only files owned by this package:
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
dcc-mcp-sketchup install --overwrite
|
|
128
|
+
dcc-mcp-sketchup uninstall
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## Skills and tools
|
|
132
|
+
|
|
133
|
+
| Skill | Tools |
|
|
134
|
+
| --- | --- |
|
|
135
|
+
| `sketchup-session` | status, inspection, root entities, save, copy, validate, import, export |
|
|
136
|
+
| `sketchup-modeling` | box, cylinder, group, transform, rename, erase, select |
|
|
137
|
+
| `sketchup-materials` | list, create, update, assign, remove |
|
|
138
|
+
| `sketchup-scenes` | list/create/update/remove scenes and Tags |
|
|
139
|
+
|
|
140
|
+
File paths must be absolute. Existing export and copy targets are refused unless
|
|
141
|
+
`overwrite=true`. Removing a material or Tag is refused while model content uses
|
|
142
|
+
it. The default Untagged Tag is never removable.
|
|
143
|
+
|
|
144
|
+
## Development and verification
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
python -m pip install -e ".[dev]"
|
|
148
|
+
python -m pytest
|
|
149
|
+
python -m ruff check src tests
|
|
150
|
+
python -m ruff format --check src tests
|
|
151
|
+
python -m build
|
|
152
|
+
python -m twine check dist/*
|
|
153
|
+
ruby tests/ruby/test_commands.rb
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
CI covers Python 3.9 through 3.12 on Windows, macOS, and Linux, plus Ruby
|
|
157
|
+
syntax and command-contract tests. A production release additionally requires a
|
|
158
|
+
real SketchUp Desktop smoke test and a fresh installation from public PyPI.
|
|
159
|
+
|
|
160
|
+
## Security boundary
|
|
161
|
+
|
|
162
|
+
- Loopback-only listener on an operating-system-assigned port.
|
|
163
|
+
- Random per-session bearer token with constant-time comparison.
|
|
164
|
+
- Correlated request IDs, deadlines, 1 MiB request/response limits, and a bounded queue.
|
|
165
|
+
- Fixed typed command allowlist; no `eval`, arbitrary Ruby, shell, or generic property access.
|
|
166
|
+
- Sidecar is bound to one SketchUp PID and stops when that host exits.
|
|
167
|
+
- Installer owns only `dcc_mcp_sketchup.rb` and the `dcc_mcp_sketchup/` directory.
|
|
168
|
+
|
|
169
|
+
## References
|
|
170
|
+
|
|
171
|
+
- [SketchUp Ruby API](https://ruby.sketchup.com/)
|
|
172
|
+
- [SketchUp extension registration tutorial](https://developer.sketchup.com/tut-hello-cube-rb)
|
|
173
|
+
- [SketchUp model API](https://ruby.sketchup.com/Sketchup/Model.html)
|
|
174
|
+
- [SketchUp UI timer API](https://ruby.sketchup.com/UI)
|
|
175
|
+
|
|
176
|
+
## License
|
|
177
|
+
|
|
178
|
+
MIT. SketchUp and its marks are property of Trimble Inc.; this project is an
|
|
179
|
+
independent integration and is not affiliated with or endorsed by Trimble.
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
# dcc-mcp-sketchup
|
|
2
|
+
|
|
3
|
+
<p align="center">
|
|
4
|
+
<picture>
|
|
5
|
+
<source media="(prefers-color-scheme: dark)" srcset="docs/assets/dcc-mcp-sketchup-dark.svg">
|
|
6
|
+
<source media="(prefers-color-scheme: light)" srcset="docs/assets/dcc-mcp-sketchup.svg">
|
|
7
|
+
<img src="docs/assets/dcc-mcp-sketchup.svg" alt="DCC-MCP · SKETCHUP" width="600">
|
|
8
|
+
</picture>
|
|
9
|
+
</p>
|
|
10
|
+
|
|
11
|
+
Production SketchUp adapter for the [DCC-MCP](https://github.com/dcc-mcp) ecosystem.
|
|
12
|
+
It combines a small Ruby extension inside SketchUp with an external Python
|
|
13
|
+
sidecar, exposing 28 typed tools without arbitrary Ruby execution.
|
|
14
|
+
|
|
15
|
+

|
|
16
|
+
|
|
17
|
+
<sub>Workflow illustration generated with OpenAI image generation; no third-party source assets.</sub>
|
|
18
|
+
|
|
19
|
+
## Capabilities
|
|
20
|
+
|
|
21
|
+
- Inspect model identity, bounds, entities, selection, and validation state.
|
|
22
|
+
- Save or copy `.skp` models and use installed SketchUp importers/exporters.
|
|
23
|
+
- Create boxes and cylinders, group, transform, rename, select, and erase entities.
|
|
24
|
+
- List, create, edit, assign, and safely remove materials.
|
|
25
|
+
- Manage saved scenes and Tags.
|
|
26
|
+
- Reference entities through SketchUp persistent IDs.
|
|
27
|
+
- Package four discoverable DCC-MCP Skills with complete JSON Schemas and MCP annotations.
|
|
28
|
+
|
|
29
|
+
## Architecture
|
|
30
|
+
|
|
31
|
+
```text
|
|
32
|
+
DCC-MCP client
|
|
33
|
+
|
|
|
34
|
+
v
|
|
35
|
+
external Python sidecar (dcc-mcp-core)
|
|
36
|
+
|
|
|
37
|
+
| authenticated, bounded JSON-RPC on 127.0.0.1
|
|
38
|
+
v
|
|
39
|
+
UI.start_timer callback on SketchUp's UI thread
|
|
40
|
+
|
|
|
41
|
+
| nonblocking, bounded socket pump + one-request queue
|
|
42
|
+
|
|
|
43
|
+
v
|
|
44
|
+
typed SketchUp Ruby API command map
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
The Ruby extension has a single socket owner: the repeating UI timer. Each tick
|
|
48
|
+
uses zero-timeout `IO.select` and nonblocking accept, read, and write operations
|
|
49
|
+
across at most 16 connections, then executes at most one validated request.
|
|
50
|
+
Frame, response, connection, and deadline limits keep every tick bounded while
|
|
51
|
+
preserving SketchUp's thread affinity. No worker thread performs socket I/O or
|
|
52
|
+
calls the SketchUp API. Every model mutation is a named undoable operation.
|
|
53
|
+
|
|
54
|
+
## Requirements
|
|
55
|
+
|
|
56
|
+
- SketchUp Desktop 2021 or newer on Windows or macOS.
|
|
57
|
+
- Python 3.9 or newer for the external sidecar.
|
|
58
|
+
- `dcc-mcp-core>=0.19.91,<1.0.0` (installed automatically).
|
|
59
|
+
|
|
60
|
+
Importer and exporter availability varies by SketchUp edition, version, and
|
|
61
|
+
installed extensions. The adapter reports the host error instead of claiming a
|
|
62
|
+
format is available when SketchUp rejects it.
|
|
63
|
+
|
|
64
|
+
## Install
|
|
65
|
+
|
|
66
|
+
Install the package into the Python environment used by DCC-MCP:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
python -m pip install dcc-mcp-sketchup
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Start SketchUp once so its versioned user profile exists, then install the Ruby
|
|
73
|
+
extension:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
dcc-mcp-sketchup install
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
For a specific SketchUp profile, pass its Plugins directory explicitly:
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
dcc-mcp-sketchup install \
|
|
83
|
+
--plugins-dir "C:/Users/you/AppData/Roaming/SketchUp/SketchUp 2026/SketchUp/Plugins"
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Restart SketchUp. The extension binds an ephemeral loopback port, generates a
|
|
87
|
+
random token, and launches the host-bound sidecar automatically. It terminates
|
|
88
|
+
the sidecar when SketchUp exits.
|
|
89
|
+
|
|
90
|
+
To update or remove only files owned by this package:
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
dcc-mcp-sketchup install --overwrite
|
|
94
|
+
dcc-mcp-sketchup uninstall
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## Skills and tools
|
|
98
|
+
|
|
99
|
+
| Skill | Tools |
|
|
100
|
+
| --- | --- |
|
|
101
|
+
| `sketchup-session` | status, inspection, root entities, save, copy, validate, import, export |
|
|
102
|
+
| `sketchup-modeling` | box, cylinder, group, transform, rename, erase, select |
|
|
103
|
+
| `sketchup-materials` | list, create, update, assign, remove |
|
|
104
|
+
| `sketchup-scenes` | list/create/update/remove scenes and Tags |
|
|
105
|
+
|
|
106
|
+
File paths must be absolute. Existing export and copy targets are refused unless
|
|
107
|
+
`overwrite=true`. Removing a material or Tag is refused while model content uses
|
|
108
|
+
it. The default Untagged Tag is never removable.
|
|
109
|
+
|
|
110
|
+
## Development and verification
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
python -m pip install -e ".[dev]"
|
|
114
|
+
python -m pytest
|
|
115
|
+
python -m ruff check src tests
|
|
116
|
+
python -m ruff format --check src tests
|
|
117
|
+
python -m build
|
|
118
|
+
python -m twine check dist/*
|
|
119
|
+
ruby tests/ruby/test_commands.rb
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
CI covers Python 3.9 through 3.12 on Windows, macOS, and Linux, plus Ruby
|
|
123
|
+
syntax and command-contract tests. A production release additionally requires a
|
|
124
|
+
real SketchUp Desktop smoke test and a fresh installation from public PyPI.
|
|
125
|
+
|
|
126
|
+
## Security boundary
|
|
127
|
+
|
|
128
|
+
- Loopback-only listener on an operating-system-assigned port.
|
|
129
|
+
- Random per-session bearer token with constant-time comparison.
|
|
130
|
+
- Correlated request IDs, deadlines, 1 MiB request/response limits, and a bounded queue.
|
|
131
|
+
- Fixed typed command allowlist; no `eval`, arbitrary Ruby, shell, or generic property access.
|
|
132
|
+
- Sidecar is bound to one SketchUp PID and stops when that host exits.
|
|
133
|
+
- Installer owns only `dcc_mcp_sketchup.rb` and the `dcc_mcp_sketchup/` directory.
|
|
134
|
+
|
|
135
|
+
## References
|
|
136
|
+
|
|
137
|
+
- [SketchUp Ruby API](https://ruby.sketchup.com/)
|
|
138
|
+
- [SketchUp extension registration tutorial](https://developer.sketchup.com/tut-hello-cube-rb)
|
|
139
|
+
- [SketchUp model API](https://ruby.sketchup.com/Sketchup/Model.html)
|
|
140
|
+
- [SketchUp UI timer API](https://ruby.sketchup.com/UI)
|
|
141
|
+
|
|
142
|
+
## License
|
|
143
|
+
|
|
144
|
+
MIT. SketchUp and its marks are property of Trimble Inc.; this project is an
|
|
145
|
+
independent integration and is not affiliated with or endorsed by Trimble.
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Architecture and host contract
|
|
2
|
+
|
|
3
|
+
The adapter has two process boundaries and one mandatory thread-affinity hop.
|
|
4
|
+
|
|
5
|
+
1. The Ruby extension loads on SketchUp's UI thread, binds an ephemeral
|
|
6
|
+
`127.0.0.1` TCP listener, generates a random token, and starts the installed
|
|
7
|
+
`dcc-mcp-sketchup` console script.
|
|
8
|
+
2. The external Python sidecar hosts `dcc-mcp-core`, binds its lifecycle to the
|
|
9
|
+
SketchUp PID, and sends only allowlisted command names over authenticated
|
|
10
|
+
newline-delimited JSON-RPC.
|
|
11
|
+
3. A repeating `UI.start_timer` callback is the only owner of accepted sockets.
|
|
12
|
+
It multiplexes at most 16 connections with zero-timeout `IO.select` and
|
|
13
|
+
nonblocking accept, read, and write operations. Complete one-line frames are
|
|
14
|
+
validated before entering a one-request queue.
|
|
15
|
+
4. The same callback executes at most one typed command per tick on SketchUp's
|
|
16
|
+
UI thread, then pumps the correlated response without blocking. There is no
|
|
17
|
+
Ruby network worker thread.
|
|
18
|
+
|
|
19
|
+
## Protocol invariants
|
|
20
|
+
|
|
21
|
+
- The listener is always loopback and uses an operating-system-assigned port.
|
|
22
|
+
- Every request carries JSON-RPC version `2.0`, a unique 32-character hex ID, a random
|
|
23
|
+
token, a typed method name, and an object-valued parameter map.
|
|
24
|
+
- Non-health requests include an absolute millisecond deadline.
|
|
25
|
+
- Requests, responses, connections, per-socket I/O, and queues are bounded.
|
|
26
|
+
- Read, request, write, and peer-close phases all have deadlines; a connection
|
|
27
|
+
carries exactly one newline-delimited request.
|
|
28
|
+
- Responses echo the request ID; the sidecar rejects mismatches.
|
|
29
|
+
- The extension launches one sidecar and terminates it on SketchUp shutdown.
|
|
30
|
+
|
|
31
|
+
## Mutation invariants
|
|
32
|
+
|
|
33
|
+
- No command evaluates source or dispatches arbitrary methods.
|
|
34
|
+
- Every model mutation is wrapped by `start_operation`, `commit_operation`, and
|
|
35
|
+
`abort_operation` on failure.
|
|
36
|
+
- Persistent IDs are the public entity reference.
|
|
37
|
+
- Destructive operations require explicit targets and are marked with MCP
|
|
38
|
+
`destructive_hint` annotations.
|
|
39
|
+
- File output rejects an existing target unless `overwrite=true`.
|
|
40
|
+
|
|
41
|
+
## Verification tiers
|
|
42
|
+
|
|
43
|
+
1. Python unit tests cover protocol validation, installer ownership, sidecar PID
|
|
44
|
+
binding, Skill validation, and manifest-to-script integrity.
|
|
45
|
+
2. Ruby tests cover syntax, the bounded command allowlist, deadlines, unit
|
|
46
|
+
conversion, persistent IDs, and undo transaction boundaries with host mocks.
|
|
47
|
+
3. Real-host acceptance uses a supported SketchUp Desktop build to create,
|
|
48
|
+
inspect, validate, save, and export geometry through typed DCC-MCP tools;
|
|
49
|
+
the exported artifact is parsed independently of SketchUp.
|
|
50
|
+
4. Cross-DCC acceptance additionally imports a supported export into another
|
|
51
|
+
live DCC when that host is available. It is reported separately and is never
|
|
52
|
+
inferred from a successful SketchUp export alone.
|
|
53
|
+
5. Release acceptance installs the published wheel from public PyPI into a new
|
|
54
|
+
environment and repeats artifact/entry-point checks.
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires=["hatchling>=1.26"]
|
|
3
|
+
build-backend="hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name="dcc-mcp-sketchup"
|
|
7
|
+
version="0.1.0"
|
|
8
|
+
description="Production SketchUp adapter with an authenticated Ruby main-thread bridge for DCC-MCP"
|
|
9
|
+
readme="README.md"
|
|
10
|
+
requires-python=">=3.9"
|
|
11
|
+
license={text="MIT"}
|
|
12
|
+
authors=[{name="loonghao",email="hal.long@outlook.com"}]
|
|
13
|
+
keywords=["sketchup","cad","3d-modeling","dcc","mcp","automation"]
|
|
14
|
+
classifiers=[
|
|
15
|
+
"Development Status :: 4 - Beta",
|
|
16
|
+
"License :: OSI Approved :: MIT License",
|
|
17
|
+
"Programming Language :: Python :: 3",
|
|
18
|
+
"Programming Language :: Python :: 3.9",
|
|
19
|
+
"Programming Language :: Python :: 3.10",
|
|
20
|
+
"Programming Language :: Python :: 3.11",
|
|
21
|
+
"Programming Language :: Python :: 3.12",
|
|
22
|
+
"Operating System :: Microsoft :: Windows",
|
|
23
|
+
"Operating System :: MacOS",
|
|
24
|
+
]
|
|
25
|
+
dependencies=["dcc-mcp-core>=0.19.91,<1.0.0"]
|
|
26
|
+
|
|
27
|
+
[project.urls]
|
|
28
|
+
Homepage="https://github.com/dcc-mcp/dcc-mcp-sketchup"
|
|
29
|
+
Repository="https://github.com/dcc-mcp/dcc-mcp-sketchup"
|
|
30
|
+
Issues="https://github.com/dcc-mcp/dcc-mcp-sketchup/issues"
|
|
31
|
+
|
|
32
|
+
[project.optional-dependencies]
|
|
33
|
+
test=["pytest>=8","ruff>=0.8","PyYAML>=6"]
|
|
34
|
+
dev=["pytest>=8","ruff>=0.8","PyYAML>=6","build>=1.2","twine>=6"]
|
|
35
|
+
|
|
36
|
+
[project.scripts]
|
|
37
|
+
dcc-mcp-sketchup="dcc_mcp_sketchup.server:main"
|
|
38
|
+
|
|
39
|
+
[project.entry-points."dcc_mcp.adapters"]
|
|
40
|
+
sketchup="dcc_mcp_sketchup:SketchupMcpServer"
|
|
41
|
+
|
|
42
|
+
[tool.hatch.build.targets.wheel]
|
|
43
|
+
packages=["src/dcc_mcp_sketchup"]
|
|
44
|
+
artifacts=["src/dcc_mcp_sketchup/skills/**","src/dcc_mcp_sketchup/sketchup_plugin/**"]
|
|
45
|
+
|
|
46
|
+
[tool.hatch.build.targets.sdist]
|
|
47
|
+
exclude=["docs/**/*.png", "docs/**/*.svg", "docs/**/*.webp"]
|
|
48
|
+
|
|
49
|
+
[tool.pytest.ini_options]
|
|
50
|
+
testpaths=["tests"]
|
|
51
|
+
pythonpath=["src","."]
|
|
52
|
+
|
|
53
|
+
[tool.ruff.lint]
|
|
54
|
+
select=["E","F","I","B"]
|
|
55
|
+
|
|
56
|
+
[tool.ruff]
|
|
57
|
+
line-length=100
|
|
58
|
+
target-version="py39"
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"packages": {
|
|
3
|
+
".": {
|
|
4
|
+
"release-type": "python",
|
|
5
|
+
"package-name": "dcc-mcp-sketchup",
|
|
6
|
+
"changelog-path": "CHANGELOG.md",
|
|
7
|
+
"include-component-in-tag": false,
|
|
8
|
+
"extra-files": [
|
|
9
|
+
{"type": "toml", "path": "pyproject.toml", "jsonpath": "$.project.version"},
|
|
10
|
+
{"type": "generic", "path": "src/dcc_mcp_sketchup/__version__.py"},
|
|
11
|
+
{"type": "generic", "path": "src/dcc_mcp_sketchup/sketchup_plugin/registration.rb"},
|
|
12
|
+
{"type": "generic", "path": "src/dcc_mcp_sketchup/skills/sketchup-session/SKILL.md"},
|
|
13
|
+
{"type": "generic", "path": "src/dcc_mcp_sketchup/skills/sketchup-modeling/SKILL.md"},
|
|
14
|
+
{"type": "generic", "path": "src/dcc_mcp_sketchup/skills/sketchup-materials/SKILL.md"},
|
|
15
|
+
{"type": "generic", "path": "src/dcc_mcp_sketchup/skills/sketchup-scenes/SKILL.md"}
|
|
16
|
+
]
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.1.0" # x-release-please-version
|