Driving SketchUp with Claude Code, Part 2 — MCP Plugin Bug Fixes
In the previous part, I got the machine ready. Now I will let Claude actually see and control SketchUp through a community MCP plugin — but the original has two bugs I want to explain up front, so you do not have to run into them one at a time like I did.
In Part 1 (machine setup), I set up the environment: Claude Code, Python, and the calculation engine. Now only the most important piece remains — the bridge that lets Claude actually "see" and "drive" SketchUp.
The connector I use is a community plugin called mhyrr/sketchup-mcp. It acts as an MCP server that Claude can call to control SketchUp. The problem is that if you use it straight from the instructions, it has 2 bugs that cost me quite a bit of time at first. I also put the files at the wrong directory level before finally getting it to run.
So I decided to explain how to prevent the bugs up front, then have Claude handle everything in one go. That way, you can skip the painful steps I went through.
1. Build the plugin correctly and avoid the bugs — one prompt does it all
My approach is to avoid fixing each issue manually, since I already know how many problems there are and where they are. So I write a detailed prompt and ask Claude to handle them all in one pass, like this.
ติดตั้งปลั๊กอิน sketchup-mcp (mhyrr) ให้ใช้กับ Claude Code ได้ถูกต้อง
จัดการประเด็นที่รู้แล้วทั้งหมดในทีเดียว:
1) โคลน repo mhyrr/sketchup-mcp branch main มาที่ D:\tools\sketchup-mcp-repo
2) อย่าใช้ wheel จาก PyPI (0.1.17 มันพังที่ FastMCP(description=...)) — ให้รัน server
จาก source เสมอด้วย uvx --from <repo> sketchup-mcp
3) patch main.rb ของ extension กัน UI freeze: เปลี่ยน socket loop จาก client.gets (blocking)
เป็น non-blocking — เขียนเมธอด read_line_bounded ที่ใช้ IO.select + read_nonblock มี deadline
ราว 2 วินาที, ห่อการรับ client ด้วย handle_client ที่ rescue ทุก error + ensure client.close,
แล้วปิด log ที่ spam console (gate ด้วย @verbose = false)
4) จัด layout ให้ถูก: su_mcp.rb (loader) + su_mcp/main.rb + su_mcp/extension.json —
repo ต้นทางวาง main.rb ซ้อนผิดชั้น (su_mcp/su_mcp/main.rb) ต้องย้ายมาให้ตรง
5) build เป็น extension-build/su_mcp.rbz พร้อมติดตั้ง
เสร็จแล้วลองรัน server ว่า startup ผ่าน (ถ้ายังไม่เปิด SketchUp จะขึ้น Could not connect to Sketchup = ปกติ)
This prompt spells out the goal and all the constraints I know about. Claude will clone the repo, fix the code, arrange the files, and build everything itself. The one line I emphasize is this — always run the server from source, never from the PyPI wheel. The actual command looks like this.
uvx --from "D:\tools\sketchup-mcp-repo" sketchup-mcp
The detail to notice is --from, which points to the repo folder I just cloned, rather than plain uvx sketchup-mcp, which would fetch the broken wheel from PyPI.
The two bugs this prompt prevents
I want you to understand why these two issues need to be addressed, because understanding the causes will help you diagnose strange behavior faster.
Bug 1 — the PyPI wheel is broken
Running uvx sketchup-mcp directly fetches wheel version 0.1.17 from PyPI. This version still contains old code and throws an error immediately on startup.
TypeError: FastMCP.__init__() got an unexpected keyword argument 'description'
The cause is that this wheel still calls FastMCP(description=...), which the newer FastMCP API has removed (replacing it with instructions=). The source code on the main branch has already been updated. That is why you need to run from the repo with --from instead of letting it fetch the wheel automatically.
Bug 2 — the plugin hangs and freezes the UI (the most important one)
This bug was the most painful and the hardest to diagnose. The original code uses blocking client.gets inside a UI.start_timer callback. The problem is that if a client connects but sends incomplete data, client.gets gets stuck waiting for data that never arrives. Because it runs on the UI thread, the entire SketchUp application freezes immediately — showing "Ruby Console Not Responding" until you close it and reopen it.
A socket loop using blocking client.gets hangs SketchUp's UI thread and freezes the entire application if a client sends incomplete data. The only way out is to restart SketchUp. This is the main reason to patch it before use.
The fix is to make the socket loop non-blocking with a read_line_bounded method that uses IO.select together with read_nonblock and sets a deadline of around 2 seconds. If the deadline passes and the data still has not arrived, it moves on instead of waiting indefinitely. Client handling is also wrapped in handle_client, which uses rescue for every error and ensure client.close to always close the socket, whatever happens. Noisy console logging is disabled by gating it with @verbose = false.
client.gets (blocking)
- Hangs the UI thread on incomplete data
- Freezes the entire SketchUp application
- Requires a restart
- Fills the console with log spam
read_line_bounded (non-blocking)
- IO.select + read_nonblock with a ~2 second deadline
- handle_client rescues every error + ensures close
- Does not hang the UI
- Disables logging with @verbose = false
One thing to remember — after patching, do not accidentally install the upstream .rbz over it, because that immediately brings the UI freeze bug back. The version you install must be built from the patched source.
If you later update the plugin directly from the upstream repo, the UI freeze bug will return. Always build from the patched source and install that version over the existing one.
2. Register MCP with Claude Code (user scope)
Once the plugin is built, the next step is to tell Claude Code that this MCP server exists. I use add-json instead of claude mcp add directly because the latter interprets --from as one of its own options, causing registration to fail. With add-json, I pass the entire config as a single JSON object, so it leaves the arguments inside alone.
$json = '{"command":"C:\\Users\\<user>\\.local\\bin\\uvx.exe","args":["--from","D:\\tools\\sketchup-mcp-repo","sketchup-mcp"]}'
claude mcp add-json sketchup $json --scope user
claude mcp list # ได้ sketchup ... Connected
I use --scope user because I want it available in every project, both in the CLI and in VS Code, without registering it again whenever I start new work. If you have registered it but still do not see the mcp__sketchup__* tools, run Reload Window first (press Ctrl+Shift+P and select Reload Window). MCP loads when the session starts, so if you register it after opening a session, it will not be visible yet.
3. Install the .rbz in SketchUp
The Claude side is ready. Now for the SketchUp side. The plugin is installed directly through Extension Manager.
- Open SketchUp, go to Window → Extension Manager → Install, and select the
extension-build\su_mcp.rbzfile you built. - Restart SketchUp 1 time so it loads the newly installed plugin.
After installation and a restart, the Extensions → MCP Server menu will appear. That means the plugin is installed successfully.
4. Start the MCP server so it is ready to use
Installing the plugin does not mean it is immediately ready to use. Before asking Claude to create a model, always open SketchUp and click Start Server first. Otherwise, Claude cannot connect.
I recommend keeping Ruby Console open to watch the logs first (Extensions → Developer → Ruby Console), so you can see the status as the server starts.
Then click Start Server (Extensions → MCP Server → Start Server; Stop Server is available to shut it down when you are done) and check Ruby Console. The last line must say server listening, like this, before it is ready.
MCP Extension loading...
MCP: Starting server on localhost:9876...
MCP: Server created on port 9876
MCP: Server started and listening <- พร้อมให้ Claude เชื่อมต่อ
Let me emphasize this — every time you use it, always open SketchUp and Start Server first. If you forget, Claude cannot connect and reports WinError 10061 connection refused, which literally means nothing is listening on that port. This is usually because you forgot to Start Server or SketchUp is closed.
If Claude cannot connect and reports connection refused, first check whether SketchUp is open and whether you have clicked Start Server. Almost every time I encounter this error, it is because I forgot to Start Server.
Claude can now drive SketchUp
With all four steps complete — building the patched plugin, registering MCP with Claude, installing the .rbz, and starting the server — Claude is ready to control SketchUp. In the next part, I will put it to work: building an entire steel building layer by layer, then sending it for FEA calculations and applying a heatmap based on the actual forces. There will also be a video of the build.
Feel free to use different paths or folder names from mine. The principles are all the same: just run the server from the patched source, and remember to Start Server before sending commands every time.
- Read Part 1 — Machine setup: /article/sketchup-claude-1-setup-pynite
- Continue to Part 3 — Build a steel building + FEA analysis: /article/sketchup-claude-3-steel-fea
Hit something like this? Stuck somewhere?
Come trade notes on the LinuxThai board



Comments 0
No comments yet — be the first