RhinoMCP
# RhinoMCP: an MCP Server for Rhino 3D
> **105 tools** for AI-driven 3D modeling, analysis, diagnostics, and Grasshopper integration via the [Model Context Protocol](https://modelcontextprotocol.io/).
RhinoMCP connects Claude to Rhino 3D through a comprehensive set of tools covering everything from basic primitives to advanced surface modeling (loft, sweep, revolve), boolean operations, mesh diagnostics, block management, and parametric design with Grasshopper.
## Architecture
```
┌────────────────┐ stdio ┌──────────────┐ TCP/JSON ┌──────────────┐
│ Claude Desktop │◄──────────►│ rhino_mcp │◄─────────────►│ Rhino 3D │
│ │ (MCP) │ (Python) │ localhost: │ listener.py │
│ │ │ server.py │ 9876 │ (inside │
└────────────────┘ └──────────────┘ │ Rhino) │
└──────────────┘
```
**MCP Server** (`rhino_mcp/`). Python package using FastMCP. Communicates with Claude via stdio and with Rhino via TCP.
**Rhino Listener** (`rhino/listener.py`). Python script that runs inside Rhino. Opens a TCP server, receives JSON commands, executes them using RhinoCommon/rhinoscriptsyntax, and returns results.
## Capabilities
### Geometry Creation (21 tools)
| Tool | Description |
|------|-------------|
| `create_point`, `create_points` | Single or batch point creation |
| `create_line`, `create_polyline` | Lines and polylines |
| `create_curve` | Interpolated NURBS curves |
| `create_circle`, `create_arc`, `create_ellipse` | Circular geometry |
| `create_rectangle` | Rectangular polylines |
| `create_sphere`, `create_box`, `create_cylinder`, `create_cone`, `create_torus` | Solid primitives |
| `create_extrusion`, `create_pipe` | Extrude and pipe along curves |
| `create_surface_from_points`, `create_mesh` | NURBS surfaces and meshes |
| `create_text` | Text dots |
| **`create_loft`** | Loft surfaces through cross-sections |
| **`create_sweep1`**, **`create_sweep2`** | Single and two-rail sweeps |
| **`create_revolve`** | Revolve profiles around an axis |
| **`create_planar_surface`**, **`create_patch`** | Planar and patch surfaces |
### Transforms (8 tools)
`move`, `rotate`, `scale`, **`scale_non_uniform`**, `mirror`, `copy`, **`array_linear`**, **`array_polar`**
### Boolean Operations (3 tools)
`boolean_union`, `boolean_difference`, `boolean_intersection`
### Modification (18 tools)
| Tool | Description |
|------|-------------|
| `delete`, `set_color`, `set_material`, `set_name`, `set_layer` | Basic modifications |
| `group`, **`ungroup`** | Grouping |
| `join`, `explode` | Join and explode geometry |
| **`trim`**, **`split`** | Trim and split curves |
| `offset_curve`, **`offset_surface`** | Offset geometry |
| **`fillet_edge`**, **`chamfer_edge`**, **`fillet_curves`** | Edge treatments |
| `cap_planar_holes` | Cap open breps |
| **`extend_curve`**, **`rebuild_curve`** | Curve editing |
| **`project_to_surface`** | Project curves onto surfaces |
| **`duplicate_edge`**, **`duplicate_border`** | Extract edges/borders |
### Blocks & Instances (4 tools)
**`create_block`**, **`insert_block`**, **`list_blocks`**, **`explode_block`**
### User Data (2 tools)
**`set_user_text`**, **`get_user_text`**: store metadata, BIM data, costs, etc.
### Layers (6 tools)
`list_layers`, `create_layer`, `delete_layer`, `set_layer_color`, `set_layer_visibility`, `set_current_layer`
### Materials (3 tools)
`list_materials`, `create_material`, `assign_material`
### Analysis (10 tools)
| Tool | Description |
|------|-------------|
| `get_bounding_box`, `get_area`, `get_volume`, `get_length` | Measurements |
| `distance`, `closest_point` | Spatial queries |
| **`intersect`** | Find intersections between objects |
| **`get_curvature`** | Curvature analysis |
| **`is_point_on_surface`**, **`is_point_in_solid`** | Point containment tests |
### Diagnostics (4 tools)
| Tool | Description |
|------|-------------|
| **`check_objects`** | Check validity, find bad geometry |
| **`get_naked_edges`** | Find gaps in surfaces |
| **`check_mesh`** | Mesh quality analysis |
| **`repair_mesh`** | Fix mesh issues automatically |
### View (5 tools)
`zoom_extents`, `set_view`, `capture_view` (with base64 option), **`list_views`**, **`set_display_mode`**
### Grasshopper (3 tools)
`gh_run_script`, `gh_set_slider`, `gh_get_outputs`
### Code Execution (2 tools)
`run_python`, `run_command`: full access to rhinoscriptsyntax and RhinoCommon
### Undo/Redo (2 tools)
`undo`, `redo`
### Scene (4 tools)
`scene_info`, `get_objects`, `get_object` (detailed with edge info), `select_objects`
### Import/Export (2 tools)
`export` (.3dm, .obj, .stl, .step, .iges, .fbx), `import_file`
**Bold** = new in v2.0
## Prerequisites
- **Rhino 7 or 8** (Windows or Mac)
- **Python 3.10+**
- **uv** package manager ([install](https://docs.astral.sh/uv/getting-started/installation/))
## Installation
### 1. Clone and install
```bash
git clone https://github.com/kbangaru-cyber/rhino-mcp.git
cd Rhino_MCP
uv sync
```
### 2. Start the Rhino listener
In Rhino:
1. Go to **Tools > PythonScript > Run**
2. Select `rhino/listener.py`
3. You should see:
```
============================================================
RhinoMCP Listener v2.0.0
Listening on 127.0.0.1:9876
Registered handlers: 90
Ready for MCP connection (Claude)
============================================================
```
### 3. Configure Claude Desktop
#### Claude Desktop
Edit `claude_desktop_config.json`:
```json
{
"mcpServers": {
"rhino": {
"command": "uv",
"args": ["--directory", "/ABSOLUTE/PATH/TO/Rhino_MCP", "run", "rhino-mcp"],
"env": {
"RHINO_MCP_HOST": "127.0.0.1",
"RHINO_MCP_PORT": "9876",
"RHINO_MCP_TIMEOUT": "30"
}
}
}
}
```
## Usage Examples
### Create a simple building form
> "Create a 10x8x4 meter box for the building volume, then add a cylinder of radius 2 and height 6 at the center for a tower. Union them together and fillet all edges with radius 0.3."
### Diagnose model problems
> "Check all objects in the scene for problems. Find any naked edges and tell me what needs fixing."
### Parametric design
> "Create a vase shape by making a profile curve and revolving it. Then create a polar array of decorative cylinders around it."
## Built-in Prompts
RhinoMCP includes guided workflow prompts:
- **`model-from-description`**: structured workflow for creating 3D models from text descriptions
- **`diagnose-model`**: systematic approach to finding and fixing model problems
- **`parametric-design`**: guide for Grasshopper/parametric workflows
## Resources
The server exposes live data as MCP resources:
| URI | Description |
|-----|-------------|
| `rhino://scene/info` | Current scene overview |
| `rhino://layers` | Layer tree |
| `rhino://materials` | Material list |
| `rhino://blocks` | Block definitions |
## Configuration
| Environment Variable | Default | Description |
|---------------------|---------|-------------|
| `RHINO_MCP_HOST` | `127.0.0.1` | Rhino listener host |
| `RHINO_MCP_PORT` | `9876` | Rhino listener port |
| `RHINO_MCP_TIMEOUT` | `30` | Command timeout (seconds) |
## Development
```bash
# Install dev dependencies
uv sync --extra dev
# Run tests (no Rhino needed)
uv run pytest -v
# Lint
uv run ruff check .
# Type check
uv run mypy rhino_mcp
```
### Integration testing
With Rhino running and the listener active:
```bash
uv run pytest -v -m integration
```
## Protocol
Commands are JSON objects sent over TCP (newline-delimited):
```json
{"id": "abc123", "action": "create_sphere", "params": {"center": [0,0,0], "radius": 5}}
```
Responses:
```json
{"id": "abc123", "ok": true, "result": {"guid": "d3e4f5..."}}
```
## Thread Safety
The Rhino listener uses `Rhino.RhinoApp.InvokeOnUiThread()` on Rhino 8+ to ensure all geometry operations run on the UI thread. On Rhino 7, operations execute directly (which is safe for single-client connections).
## License
MIT. See [`LICENSE`](LICENSE).
## Author
**Karthick Raja B G**, [portfolio](https://sites.google.com/view/karthick-raja/home) · [GitHub](https://github.com/kbangaru-cyber)
Related work: [SPIDER](https://github.com/kbangaru-cyber/SPIDER), a Grasshopper plugin for
computational geometry and spatial analysis.
TDQS
Scored across 105 tools
Most geometry creation/editing tools are distinguishable by their object type and operation, but the set contains direct duplicates (set_material/assign_material, duplicate_border/get_naked_edges) and overlapping checks (check_objects/check_mesh). With 105 tools, an agent must navigate many near-synonyms and the line between trim/split and copy/array is not always obvious.
Tools consistently use the rhino_ prefix with snake_case verb_noun operations, making groups like create_* and get_* easy to scan. Minor inconsistencies exist (scene_info is noun-only, distance/intersect have no target, set_material vs assign_material) but they do not undermine the overall pattern.
At 105 tools, this is an extreme mismatch for an MCP tool surface, far beyond the 25+ threshold where selection overhead becomes severe. Many narrow variants (e.g., point vs points, multiple sweep/loft surface creators) could be consolidated without losing capability.
The server covers the full Rhino modeling lifecycle: primitive creation, editing, transformations, booleans, analysis, layers, materials, blocks, Grasshopper, and file I/O. Minor gaps like layer rename/lock or block definition removal exist, but the universal run_python and run_command escape hatches prevent dead ends.