Sketchup integration through Model Context Protocol
Project description
SketchupMCP
Connect Claude (or any MCP-aware AI client) to SketchUp for prompt-driven 3D modeling.
Two-process bridge:
- Python MCP server (
sketchup-mcp2on PyPI) — exposes typed tools to the LLM via the Model Context Protocol. - Ruby SketchUp extension — runs a TCP server inside SketchUp and executes commands against the live model.
Quickstart
1. Install the SketchUp extension
Either grab the latest .rbz from GitHub Releases or build it from source:
gem install --user-install rubyzip
cd su_mcp && ruby package.rb
# → su_mcp/su_mcp_v<version>.rbz
In SketchUp: Window → Extension Manager → Install Extension, pick the .rbz, restart SketchUp.
2. Start the server inside SketchUp
Plugins → MCP Server → Start — by default listens on 127.0.0.1:9876.
3. Configure your MCP client
For Claude Code / Claude Desktop, add to .mcp.json (or claude_desktop_config.json):
{
"mcpServers": {
"sketchup": {
"command": "uvx",
"args": ["sketchup-mcp2"],
"env": {
"SKETCHUP_MCP_HOST": "127.0.0.1",
"SKETCHUP_MCP_PORT": "9876",
"SKETCHUP_MCP_TIMEOUT": "60",
"SKETCHUP_MCP_LOG_LEVEL": "INFO"
}
}
}
}
uvx will pull sketchup-mcp2 from PyPI automatically — install uv if you don't have it.
That's it. Ask Claude things like "create a 1.2 × 0.8 m oak dining table" and watch it happen.
Features
Tool catalogue
| Category | Tools |
|---|---|
| Geometry | create_component (cube / cylinder / cone / sphere), delete_component, transform_component — all dimensions in mm |
| Materials | set_material — named colors and hex #rrggbb |
| Booleans | boolean_operation — union / difference / intersection |
| Edge ops | chamfer_edge, fillet_edge — distance/radius in mm, segments configurable |
| Joinery | create_mortise_tenon, create_dovetail, create_finger_joint |
| Export | export_scene — skp / obj / dae / stl / png / jpg |
| Introspection | get_model_info, list_components, get_component_info, find_components, list_layers, create_layer, get_selection, get_version |
| View | get_viewport_screenshot — captures the viewport as a PNG (returns an MCP Image; optional view_preset / style / zoom_extents; requires SketchUp 2026+) |
| Lifecycle | undo |
| Escape hatch | eval_ruby — arbitrary Ruby inside SketchUp for anything not covered above |
All dimensions in millimeters; angles in degrees. Every entity-returning handler also responds with bbox_mm so the LLM can re-locate entities by bounding box if their IDs go stale after destructive ops.
Capabilities
- Multi-client support — N concurrent MCP clients can be connected at once (e.g. Claude Desktop + a smoke-test script + your own Python notebook). Operations are still serialised on the SketchUp UI thread; frames are dispatched in a single global FIFO ordered by decode arrival.
- One-time version handshake — every TCP connection begins with a JSON-RPC
hellocarryingclient_version; the server validates against its supported range and replies withserver_version+client_id. Incompatible pairs surface immediately asIncompatibleVersionErrorand the socket is closed. - Atomic undo — every mutating handler wraps the edit in
model.start_operation/commit_operation, so a singleEdit → Undorolls back the whole call. - MCP prompt
sketchup_modeling_strategy— surfaced in MCP-aware clients' slash menu; teaches the model project conventions (mm units, typed-tools-vs-eval_ruby, pitfalls like reversedGroup#subtract). - Settings dialog —
Plugins → MCP Server → Settings...for host / port / log level. Log level applies immediately; host/port changes prompt for a restart.
Configuration
Python side (env vars in .mcp.json)
| Variable | Default | Description |
|---|---|---|
SKETCHUP_MCP_HOST |
127.0.0.1 |
Where to connect to the SketchUp extension |
SKETCHUP_MCP_PORT |
9876 |
TCP port |
SKETCHUP_MCP_TIMEOUT |
60 |
Per-tool-call timeout (seconds) |
SKETCHUP_MCP_LOG_LEVEL |
INFO |
DEBUG / INFO / WARN / ERROR |
Ruby side (Settings dialog inside SketchUp)
Open Plugins → MCP Server → Settings... to change Host, Port, and Log Level. Values persist in SketchUp's preferences under section SU_MCP. No environment variables are read on the Ruby side.
⚠ Security warning: binding the host to
0.0.0.0exposes the MCP server — includingeval_ruby, which runs arbitrary Ruby inside SketchUp — to the entire local network with no authentication. Use only on trusted networks (host → VM, isolated lab). For multi-machine setups consider a loopback SSH tunnel instead.
Examples
Things you can ask Claude:
- "Create a simple dining table — 1.2 × 0.8 m, 760 mm tall, oak finish"
- "Highlight every component smaller than 100 mm in any dimension"
- "Make the selected component red, then move it 100 mm up"
- "Export the scene as STL for 3D printing"
- "Build a small arts-and-crafts cabinet using
eval_rubywith dovetails"
For richer Ruby recipes that drive the SketchUp API directly — framed walls, gable/hip roofs, joist arrays, follow_me extrusions, world-space transforms, common pitfalls — see docs/sketchup-ruby-cookbook.md.
Working examples and load tests live in examples/:
smoke_check.py— 22-step end-to-end verification of every tool category.smoke_multi_client.py— concurrent multi-client load test.arts_and_crafts_cabinet.py— a non-trivial generative model viaeval_ruby.simple_test.py,simple_ruby_eval.py,behavior_tester.py— minimal scaffolds.
Architecture
Claude (MCP client)
↕ MCP (stdio)
Python MCP server (FastMCP) src/sketchup_mcp/
↕ TCP — JSON-RPC 2.0, 4-byte big-endian length-prefix framing, 64 MiB cap
Ruby SketchUp extension (server) su_mcp/su_mcp/
↕ SketchUp Ruby API
Live SketchUp model
The Ruby side runs entirely on the SketchUp UI thread via UI.start_timer callbacks (SketchUp's Ruby is single-threaded — no native threads allowed). The Python side holds one persistent TCP socket per process and serialises tool-calls with an asyncio.Lock.
Source layout:
- Python:
src/sketchup_mcp/{tools,connection,config,compat,errors,prompts}.py - Ruby:
su_mcp/su_mcp/{core,handlers,helpers,ui}/
See CLAUDE.md for the project's working notes and non-obvious constraints (unit conversions, reversed boolean semantics, framing details, etc.).
Development
Python package (editable install)
uv pip install -e .
python -m sketchup_mcp # direct
uvx sketchup-mcp2 # production-style (from PyPI)
Tests
ruby test/run_all.rb # Ruby unit tests (minitest, stdlib only)
uv run pytest tests/ -q # Python unit tests
Live smoke (requires SketchUp running with the extension started)
uv run python examples/smoke_check.py # 22-step end-to-end
uv run python examples/smoke_multi_client.py # concurrent multi-client
For a split-host setup (e.g. Linux dev box + Windows SketchUp), prefix with SKETCHUP_MCP_HOST=<sketchup-host>.
Troubleshooting
SketchUp not running or extension not started: ...
The Python MCP server connected to the configured host/port but found nothing listening. Either:
- SketchUp isn't running, or
- The extension is installed but not started — open
Plugins → MCP Server → Start.
The Python server stays alive after this error; the next tool-call retries the connect.
IncompatibleVersionError
Your installed sketchup-mcp2 Python package and the .rbz extension are outside the supported version range. Rebuild the .rbz from the same commit as the Python package, or pip install -U sketchup-mcp2. The current supported range lives in src/sketchup_mcp/compat.py and su_mcp/su_mcp/core/compat.rb.
Tool-call timeouts on long operations
Bump SKETCHUP_MCP_TIMEOUT in your .mcp.json env block. Default is 60 seconds.
SketchUp UI freezes during big requests
Frame-decoding is capped at 50 reads × 64 KiB per client per tick (~3.2 MB) to keep the UI responsive, but a very large eval_ruby body or a runaway loop inside it will still freeze SketchUp until it returns. Break the work into smaller calls if you can.
License
MIT — see LICENSE.
Credits and attribution
- Originally forked from mhyrr/sketchup-mcp. The fork diverged at v0.0.1 with a new wire protocol (4-byte length-prefix framing, JSON-RPC 2.0 envelopes), modular handler architecture, expanded introspection / joinery / edge-op tools, multi-client server with one-time
hellohandshake, MCP prompt, viewport screenshot, settings dialog, and full unit-test coverage on both Ruby and Python sides. - Published to PyPI as
sketchup-mcp2; the upstream package issketchup-mcp. - Bridge-pattern inspiration from ahujasid/blender-mcp.
Contributing
Pull requests welcome. Before opening one, please run both test suites (ruby test/run_all.rb and uv run pytest tests/) and — if you've touched anything in the IO path — the live smokes against a running SketchUp.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file sketchup_mcp2-0.1.0.tar.gz.
File metadata
- Download URL: sketchup_mcp2-0.1.0.tar.gz
- Upload date:
- Size: 45.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a29b2d88a48829f7039a53c20005498ff48dd58bcef6b4470400687b725caa46
|
|
| MD5 |
e5d6f93a3971ee0cf70b394fb4b491e6
|
|
| BLAKE2b-256 |
bb191fa1282f4dfd47df36b5098675c991caaa4da005f35811c35ac8008bca37
|
File details
Details for the file sketchup_mcp2-0.1.0-py3-none-any.whl.
File metadata
- Download URL: sketchup_mcp2-0.1.0-py3-none-any.whl
- Upload date:
- Size: 26.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
409a67751ae4e51ed439c23c74907762e80952bcd8b9c481c0c37706ab274d15
|
|
| MD5 |
3864e4baa1dc0541dabd74960ee1f65e
|
|
| BLAKE2b-256 |
e55502ef1554e6195379808392ed17a3aacc001bf2b816d19b2b53a98859b0d3
|