Metadata-Version: 2.5
Name: dcc-mcp-sketchup
Version: 0.2.0
Summary: Production SketchUp adapter with an authenticated Ruby main-thread bridge for DCC-MCP
Project-URL: Homepage, https://github.com/dcc-mcp/dcc-mcp-sketchup
Project-URL: Repository, https://github.com/dcc-mcp/dcc-mcp-sketchup
Project-URL: Issues, https://github.com/dcc-mcp/dcc-mcp-sketchup/issues
Project-URL: Installation, https://raw.githubusercontent.com/dcc-mcp/dcc-mcp-sketchup/main/install.md
Author-email: loonghao <hal.long@outlook.com>
License: MIT
License-File: LICENSE
Keywords: 3d-modeling,automation,cad,dcc,mcp,sketchup
Classifier: Development Status :: 4 - Beta
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: MacOS
Classifier: Operating System :: Microsoft :: Windows
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Requires-Python: >=3.9
Requires-Dist: dcc-mcp-core<1.0.0,>=0.20.14
Provides-Extra: dev
Requires-Dist: build>=1.2; extra == 'dev'
Requires-Dist: jsonschema>=4.23; extra == 'dev'
Requires-Dist: pytest>=8; extra == 'dev'
Requires-Dist: pyyaml>=6; extra == 'dev'
Requires-Dist: ruff>=0.8; extra == 'dev'
Requires-Dist: twine>=6; extra == 'dev'
Provides-Extra: test
Requires-Dist: jsonschema>=4.23; extra == 'test'
Requires-Dist: pytest>=8; extra == 'test'
Requires-Dist: pyyaml>=6; extra == 'test'
Requires-Dist: ruff>=0.8; extra == 'test'
Description-Content-Type: text/markdown

# dcc-mcp-sketchup

<p align="center">
  <picture>
    <source media="(prefers-color-scheme: dark)" srcset="docs/assets/dcc-mcp-sketchup-dark.svg">
    <source media="(prefers-color-scheme: light)" srcset="docs/assets/dcc-mcp-sketchup.svg">
    <img src="docs/assets/dcc-mcp-sketchup.svg" alt="DCC-MCP · SKETCHUP" width="600">
  </picture>
</p>

Production SketchUp adapter for the [DCC-MCP](https://github.com/dcc-mcp) ecosystem.
It combines a small Ruby extension inside SketchUp with an external Python
sidecar, exposing 28 typed tools without arbitrary Ruby execution.

![Typed SketchUp model inspection, construction, organization, validation, and interchange export](docs/images/sketchup-showcase.webp)

<sub>Workflow illustration generated with OpenAI image generation; no third-party source assets.</sub>

## Capabilities

- Inspect model identity, bounds, entities, selection, and validation state.
- Save or copy `.skp` models and use installed SketchUp importers/exporters.
- Create boxes and cylinders, group, transform, rename, select, and erase entities.
- List, create, edit, assign, and safely remove materials.
- Manage saved scenes and Tags.
- Reference entities through SketchUp persistent IDs.
- Package four discoverable DCC-MCP Skills with complete JSON Schemas and MCP annotations.

## Architecture

```text
DCC-MCP client
      |
      v
external Python sidecar (dcc-mcp-core)
      |
      | authenticated, bounded JSON-RPC on 127.0.0.1
      v
UI.start_timer callback on SketchUp's UI thread
      |
      | nonblocking, bounded socket pump + one-request queue
      |
      v
typed SketchUp Ruby API command map
```

The Ruby extension has a single socket owner: the repeating UI timer. Each tick
uses zero-timeout `IO.select` and nonblocking accept, read, and write operations
across at most 16 connections, then executes at most one validated request.
Frame, response, connection, and deadline limits keep every tick bounded while
preserving SketchUp's thread affinity. No worker thread performs socket I/O or
calls the SketchUp API. Every model mutation is a named undoable operation.

## Requirements

- SketchUp Desktop 2021 or newer on Windows or macOS.
- Python 3.9 or newer for the external sidecar.
- `dcc-mcp-core>=0.20.14,<1.0.0` (installed automatically).

Importer and exporter availability varies by SketchUp edition, version, and
installed extensions. The adapter reports the host error instead of claiming a
format is available when SketchUp rejects it.

## Install

See the [Install and lifecycle runbook](install.md) for the agent-first JSON contract, supported
host versions, verification, transactional upgrade, receipt-driven uninstall, and troubleshooting.

Install the package into the Python environment used by DCC-MCP:

```bash
python -m pip install dcc-mcp-sketchup
```

Start SketchUp once so its versioned user profile exists, inspect the JSON plan,
then install the Ruby extension:

```bash
dcc-mcp-sketchup install --dcc-path "C:/Program Files/SketchUp/SketchUp 2026/SketchUp.exe" --json --dry-run
dcc-mcp-sketchup install --dcc-path "C:/Program Files/SketchUp/SketchUp 2026/SketchUp.exe" --json --yes
```

Use `--python` when the sidecar belongs to another Python environment. The
installer selects the versioned profile matching `--dcc-path`, writes a receipt,
and verifies files, importability, bootstrap state, and the live host probe.

Open or restart SketchUp after installation. The extension binds an ephemeral
loopback port, generates a random token, and launches the host-bound sidecar
automatically. It terminates the sidecar when SketchUp exits.

To update or remove only files owned by this package:

```bash
dcc-mcp-sketchup upgrade --dcc-path "C:/Program Files/SketchUp/SketchUp 2026/SketchUp.exe" --json --yes
dcc-mcp-sketchup uninstall --dcc-path "C:/Program Files/SketchUp/SketchUp 2026/SketchUp.exe" --json --yes
```

## Skills and tools

| Skill | Tools |
| --- | --- |
| `sketchup-session` | status, inspection, root entities, save, copy, validate, import, export |
| `sketchup-modeling` | box, cylinder, group, transform, rename, erase, select |
| `sketchup-materials` | list, create, update, assign, remove |
| `sketchup-scenes` | list/create/update/remove scenes and Tags |

File paths must be absolute. Existing export and copy targets are refused unless
`overwrite=true`. Removing a material or Tag is refused while model content uses
it. The default Untagged Tag is never removable.

## Development and verification

```bash
python -m pip install -e ".[dev]"
python -m pytest
python -m ruff check src tests
python -m ruff format --check src tests
python -m build
python -m twine check dist/*
ruby tests/ruby/test_commands.rb
```

CI covers Python 3.9 through 3.12 on Windows, macOS, and Linux, plus Ruby
syntax and command-contract tests. A production release additionally requires a
real SketchUp Desktop smoke test and a fresh installation from public PyPI.

## Security boundary

- Loopback-only listener on an operating-system-assigned port.
- Random per-session bearer token with constant-time comparison.
- Correlated request IDs, deadlines, 1 MiB request/response limits, and a bounded queue.
- Fixed typed command allowlist; no `eval`, arbitrary Ruby, shell, or generic property access.
- Sidecar is bound to one SketchUp PID and stops when that host exits.
- Installer owns only `dcc_mcp_sketchup.rb` and the `dcc_mcp_sketchup/` directory.

## References

- [SketchUp Ruby API](https://ruby.sketchup.com/)
- [SketchUp extension registration tutorial](https://developer.sketchup.com/tut-hello-cube-rb)
- [SketchUp model API](https://ruby.sketchup.com/Sketchup/Model.html)
- [SketchUp UI timer API](https://ruby.sketchup.com/UI)

## License

MIT. SketchUp and its marks are property of Trimble Inc.; this project is an
independent integration and is not affiliated with or endorsed by Trimble.
