Skip to content
EaseHeePublic

About

MCP Server for Rhino and Grasshopper

Topics

Resources

Contributing

Stars

8 stars

Watchers

2 watching

Forks

Repository files navigation

rhino-logo

rhino-mcp

Drive McNeel Rhino 8 and Grasshopper from Claude through the Model Context Protocol.

PyPI Python License Rhino MCP Platform

English · 한국어


Overview

rhino-mcp is a Model Context Protocol server that lets Claude (or any MCP client) drive Rhino 8 — creating geometry, manipulating layers and materials, baking Grasshopper output, exporting STEP/IGES/STL/OBJ — through plain natural-language tool calls. It runs in two modes:

  • Standalone (default): backed by rhino3dm for headless .3dm file authoring; works without Rhino installed and exposes ~242 tools (geometry, file-I/O, transform, layer, material, analysis, RhinoScript docs, composition, document hygiene, geometry validation, GH template catalogue, freeform skin / panelisation / curvature / fields, drawing-set sheet + title block, schedule / quantity, block definition, sun-position + shadow projection, BIM metadata tagging, 19 physical material presets, BRE daylight factor + Bird DNI clear-sky model, and multi-Rhino announcement-file discovery).
  • Bridge: when the C# bridge plugin is loaded in a live Rhino 8 session, the server transparently forwards every call (booleans, lofts, sweeps, viewport image capture + zoom-to-object / zoom-to-layer, render, scripting (Python and gated Roslyn C# with timeouts and extra references), deformation, NURBS editing, SubD, paneling, freeform analysis with true Gaussian curvature, drawing-set view placement + section cuts + PDF export, accurate Brep-area schedules, block explode/redefine, ray-cast solar exposure + Brep ray probe, IFC / gbXML import-export, HDRI environment, camera / light / render / turntable automation, layer-material binding, and every Grasshopper operation including batched connect_many wiring and slider placement) to RhinoCommon and Grasshopper.Instances, exposing ~245 tools.

Features

  • Full geometry catalogue — points, lines, polylines, arcs, circles, ellipses, polygons, helixes, NURBS curves, rebuilds.
  • Solids and meshes — boxes, spheres, cylinders, cones, tori, mesh boxes; booleans / sweeps / lofts / fillets via the bridge.
  • Transforms — move, rotate, scale, mirror, plane-to-plane orient, linear/polar/rectangular arrays.
  • Script execution — run arbitrary RhinoScript Python (IronPython) or RhinoCommon C# (Roslyn) code in a live Rhino session, with built-in RhinoScript API documentation search (899 functions).
  • Advanced modeling — deformation (bend/twist/taper/flow), NURBS editing (rebuild/unroll/evaluate), SubD, surface matching, extraction (dup edge/border/isocurve/Make2D), control points, and paneling tools.
  • Drawing-set authoring — sheet / title block / north arrow / scale bar in standalone; multi-view placement, section cuts, and PDF export through the bridge.
  • Quantity & schedule — per-layer / per-material / per-user_text aggregation with CSV export; bridge mode uses AreaMassProperties / VolumeMassProperties for accurate Brep area + volume.
  • Block / instance reuse — define / insert / list blocks in standalone; explode / redefine in bridge mode for synchronized component edits.
  • Environmental analysis — sun position + monthly sun-path polylines + shadow projection (NOAA SPA approximation); ray-cast solar exposure in bridge mode. Daylight precision adds Bird DNI clear-sky model with Kasten-Young air mass and Linke turbidity, plus BRE simplified daylight factor.
  • BIM interchange — IFC2x3 / IFC4 / IFC4x3 import & export, gbXML export, and IFC PropertySet metadata tagging that round-trips through user_text.
  • Material presets + HDRI — 19 bundled physical presets (concrete / brick / steel / aluminium / glass / timber / stone / plaster / fabric / landscape) keyed by category; HDRI environment for rendering.
  • Render automation — camera / light / render-engine setup, render-to-file, and parametric turntable sequences (bridge mode).
  • Undo / redo and batch operations — every bridge operation is wrapped in undo records; batch modify changes many objects in a single call.
  • Layers, materials, blocks, groups — full attribute control on the document.
  • File I/O — open/save .3dm, export OBJ/STL standalone; STEP/IGES/DXF and screenshots via the bridge.
  • Inline base64 screenshots — rhino_screenshot(as_base64=True) returns the PNG payload inline for visual verification by the LLM.
  • Rich object selection — rhino_object_select filters by glob name pattern, layer, RGB color, object type, and user-text key/value pairs.
  • Pagination on bulk queries — rhino_list_objects returns a pagination: {total, offset, limit, returned, has_more} block so large documents stay manageable.
  • Scene composition shortcuts (v0.2) — rhino_place_grid, rhino_stack_floors, rhino_scatter, rhino_replicate_along_curve collapse "loop + transform" into a single tool call.
  • Document hygiene tools (v0.2) — query/set units, tolerances, and base point (rhino_document_units_*, rhino_tolerance_*, rhino_origin_set); rhino_document_summary exposes them so the LLM can verify scale before issuing geometry calls.
  • Geometry validation (v0.2) — rhino_validate_brep, rhino_report_mesh_health, rhino_curve_continuity, plus rhino_check_naked_edges (bridge) for explicit topology diagnostics before booleans / exports.
  • Grasshopper template loader (v0.2) — gh_template_list reads a manifest of pre-wired definitions; gh_load_template, gh_bind_template_parameter, gh_run_template (bridge) load, parameterise, and bake them.
  • Free-form architecture toolkit — rhino_skin_from_sections, rhino_uv_grid_panels, rhino_panel_planarity, rhino_panel_curvature_classify, rhino_surface_developable_score, rhino_attractor_displace_points, rhino_smooth_polyline. Bridge mode adds true Gaussian / mean / principal curvature, world-axis slicing, and waffle ribs.
  • Strategy prompts for the LLM — seven @mcp.prompt() guides (general_strategy, rhinoscript_workflow, viewport_workflow, parametric_workflow, bim_authoring_workflow, design_dialogue_workflow, freeform_workflow) help Claude pick the right tool, avoid hallucinated APIs, and keep the user in the loop on design decisions.
  • Async-capable tools — read-only query tools run on async def so concurrent bridge round-trips don't stall the MCP transport.
  • Robust connection layer — JSON-RPC over named pipe / Unix socket / TCP with MSG_PEEK liveness probes and exponential backoff with jitter on reconnect.
  • Grasshopper automation — open .gh files, drop components, wire them, set sliders/panels/toggles, run, bake, read DataTrees.
  • Three transports — stdio (Claude Desktop), Streamable HTTP, Docker/TCP.
  • Capability-aware registration — bridge-only tools are simply not registered when no bridge is reachable; no stub functions, ever.
  • Actionable errors — every failure carries a category, a remediation hint, and details the agent can act on.

Architecture

┌──────────────┐     stdio | HTTP     ┌────────────────┐
│  Claude /    │ ◀──────────────────▶ │   rhino-mcp    │
│  MCP client  │                      │   (Python)     │
└──────────────┘                      └─────┬──────────┘
                                            │
                              JSON-RPC 2.0  │   (named pipe / unix socket / TCP)
                                            │
                                  ┌─────────▼──────────┐
                                  │  C# Bridge Plugin  │
                                  │  (inside Rhino 8)  │
                                  │  ────────────────  │
                                  │  RhinoCommon       │
                                  │  Grasshopper       │
                                  │  Roslyn (C# exec)  │
                                  │  IronPython (Py)   │
                                  └────────────────────┘

In standalone mode the right-hand side is replaced by an in-process rhino3dm.File3dm document; bridge-only tools are unregistered.

Requirements

  • Python 3.11 or newer
  • rhino3dm >= 8.9, mcp[cli] >= 1.2, pydantic >= 2.6 (installed automatically)
  • Optional: McNeel Rhino 8 (any platform) — needed only for bridge mode
  • Optional: .NET 8 SDK — to build the C# bridge plugin (dotnet build)
  • Optional: pywin32 on Windows for the named-pipe transport

Installation

Using uv (recommended)

uv tool install rhino-mcp
# or, from a checkout:
uv sync && uv run rhino-mcp

Using pip

pip install rhino3dm-mcp
rhino-mcp --version

One-shot Claude Desktop wiring

After installing the package, register the server with Claude Desktop in a single command instead of editing claude_desktop_config.json by hand:

rhino-mcp install                         # auto-detect launcher (uvx / rhino-mcp / python)
rhino-mcp install --mode bridge           # force bridge mode in the env block
rhino-mcp install --force                 # overwrite an existing entry
rhino-mcp install --dry-run               # preview the JSON without writing

The command writes a timestamped .bak.* copy of the existing config before saving, and is idempotent — re-running with the same flags is a no-op. Restart Claude Desktop afterwards to pick up the change.

From inside Rhino — _McpInstall

If the bridge plugin is loaded, type _McpInstall on the Rhino command line. The command is non-interactive: it locates uvx / rhino-mcp / python on PATH (with ~/.local/bin, ~/.cargo/bin, /opt/homebrew/bin, and /usr/local/bin searched on macOS so the GUI-app PATH is enough), runs the same install pipeline as rhino-mcp install, and streams the outcome to the Rhino command line. The MCP server is registered with --mode auto so Claude Desktop attaches to the bridge when Rhino is running and falls back to standalone (rhino3dm) when it is not.

Docker

docker compose -f docker/docker-compose.yml up --build

The container exposes the server over Streamable HTTP on TCP :8765.

Running the server

rhino-mcp is normally launched by an MCP client (Claude Desktop / Cursor / claude.ai connector) via the command + args you put into the client's config. You can also run it manually for debugging.

Launch modes

Use case Command
Stdio (Claude Desktop default) uvx rhino3dm-mcp or rhino-mcp
Streamable HTTP (local dev / Cursor) rhino-mcp --transport http --host 127.0.0.1 --port 8765
Streamable HTTP (claude.ai connector) rhino-mcp --transport http --host 0.0.0.0 --port 8765 --allow-external --stateless
Docker (HTTP on :8765) docker compose -f docker/docker-compose.yml up --build
Force standalone (no Rhino needed) RHINO_MCP_FORCE_MODE=standalone rhino-mcp
Force bridge (fail fast if Rhino down) RHINO_MCP_FORCE_MODE=bridge rhino-mcp
Force bridge with HTTP fallback RHINO_MCP_FORCE_MODE=bridge RHINO_MCP_BRIDGE_OPTIONAL=1 rhino-mcp --transport http
Show all CLI flags rhino-mcp --help

The HTTP endpoint is http://<host>:<port>/mcp. Use --allow-external only when exposing the server through ngrok / Cloudflare Tunnel / etc. — it disables DNS-rebinding protection.

Claude Desktop (stdio)

claude_desktop_config.json lives at:

OS Path
macOS ~/Library/Application Support/Claude/claude_desktop_config.json
Windows %APPDATA%\Claude\claude_desktop_config.json
Linux ~/.config/Claude/claude_desktop_config.json

Paste this entry under mcpServers:

{
  "mcpServers": {
    "rhino-mcp": {
      "command": "uvx",
      "args": ["rhino3dm-mcp"],
      "env": {
        "RHINO_MCP_TRANSPORT": "stdio",
        "RHINO_HOST": "127.0.0.1",
        "RHINO_PORT": "4242",
        "RHINO_MCP_LOG_LEVEL": "INFO"
      }
    }
  }
}

Prefer a checkout? Point command at uv and run from the repo:

{
  "mcpServers": {
    "rhino-mcp": {
      "command": "uv",
      "args": ["--directory", "/absolute/path/to/rhino-mcp", "run", "rhino-mcp"],
      "env": { "RHINO_MCP_LOG_LEVEL": "DEBUG" }
    }
  }
}

Restart Claude Desktop; the rhino-mcp tools and the three strategy prompts (general_strategy, rhinoscript_workflow, viewport_workflow) appear in the palette.

Cursor IDE

Cursor reads ~/.cursor/mcp.json (global) or <project>/.cursor/mcp.json (per-project):

{
  "mcpServers": {
    "rhino-mcp": {
      "command": "uvx",
      "args": ["rhino3dm-mcp"],
      "env": { "RHINO_MCP_FORCE_MODE": "bridge" }
    }
  }
}

claude.ai remote connector (Streamable HTTP)

  1. Run the server with HTTP + external access:

    rhino-mcp --transport http --host 0.0.0.0 --port 8765 --allow-external --stateless
  2. Tunnel it (e.g. ngrok http 8765) and grab the public HTTPS URL.

  3. In claude.ai → Settings → Connectors → Add custom connector, set the URL to https://<your-tunnel>/mcp.

Generic stdio MCP clients

Any MCP-compatible client (mcp-inspector, Continue, Claude Code, etc.) that can spawn a subprocess will work — give it uvx rhino3dm-mcp or the path to your rhino-mcp entry-point and inherit env vars from the table below.

Rhino-side bridge plugin (C# — recommended)

Build and install the C# plugin for full 235 tool support. The included helper script wraps dotnet build and verifies the post-build install location:

./scripts/build-plugin.sh             # debug build + install
./scripts/build-plugin.sh --release   # release build
./scripts/build-plugin.sh --clean     # clean + rebuild

# Or invoke dotnet directly:
dotnet build rhino_plugin/csharp/RhinoMCPPlugin.csproj -c Release

Post-build targets copy the .rhp:

OS Path
macOS /Applications/Rhino 8.app/Contents/PlugIns/rhino-mcp.rhp
Windows %APPDATA%/McNeel/Rhinoceros/8.0/Plug-ins/rhino-mcp/rhino-mcp.rhp

Restart Rhino 8 — the bridge starts automatically on load (TCP :4242 by default). Then restart rhino-mcp (or set RHINO_MCP_FORCE_MODE=bridge) and the bridge-only tools become available.

Quick start

# After "rhino-mcp" is configured in Claude Desktop, ask Claude:
#   "Create a 10-unit sphere at the origin and save the document to /tmp/demo.3dm"
# Behind the scenes Claude calls rhino_sphere → rhino_save.

Strategy prompts

Three MCP prompts are registered automatically and surfaced in the client's prompt picker:

Prompt When to use
general_strategy Decision tree for orienting in a document → choosing the right tool → best practices.
rhinoscript_workflow Mandatory steps before invoking rhino_execute_python so the LLM doesn't hallucinate APIs.
viewport_workflow How to combine rhino_zoom_extent + rhino_screenshot(as_base64=True) for visual checks.

Telling Claude "use the general_strategy prompt before you start" gives much better tool selection on long sessions.

Visual verification with base64 screenshots

"Build a 5x5x5 box on layer 'Demo', then take a 1280x720 base64 screenshot so you can confirm it landed."

Claude calls rhino_box → rhino_zoom_extent → rhino_screenshot(as_base64=True) and reads the inline PNG from the response (image_base64 field) on the next turn.

Pagination & rich filtering

"List the first 50 curves on the 'Walls' layer, then select every object whose name matches 'Pillar_*' on layer 'Structure'."

rhino_list_objects returns a pagination block; iterate with offset += limit until has_more is false. rhino_object_select accepts name_pattern, layer, color, object_type, user_text, and deselect_first.

Standalone smoke run from the shell:

RHINO_MCP_FORCE_MODE=standalone uv run python - <<'PY'
import asyncio
from rhino_mcp.server import build_server
from rhino_mcp.utils.registry import Mode

mcp, count = build_server(runtime_mode=Mode.STANDALONE, bridge_client=None)
print(f"{count} tools registered")
sphere = asyncio.run(
    mcp._tool_manager._tools["rhino_sphere"].run(
        {"args": {"center": {"x": 0, "y": 0, "z": 0}, "radius": 10.0}}
    )
)
print(sphere)
PY

Tools reference (summary)

Category Standalone + Bridge Notable members
Geometry 14 14 rhino_point, rhino_circle, rhino_helix, rhino_nurbs_curve, rhino_rebuild_curve
Curves 3 3 rhino_curve_length, rhino_curve_point_at, rhino_curve_split
Solids 5 10 rhino_box, rhino_sphere, rhino_boolean_union (bridge)
Surfaces 0 11 rhino_loft, rhino_sweep1, rhino_revolve
Mesh 1 8 rhino_mesh_box, rhino_weld_mesh (bridge)
Transform 9 11 rhino_array_polar, rhino_orient, rhino_flow (bridge)
Annotation 2 8 rhino_text_dot, rhino_dimension_linear (bridge)
Layer / Object 6 8 rhino_layer_create, rhino_block_insert (bridge)
Material 2 3 rhino_material_create, rhino_render_viewport (bridge)
File I/O 5 9 rhino_save, rhino_export_step (bridge)
Analysis 4 9 rhino_volume, rhino_zebra (bridge)
Query 7 8 rhino_list_objects, rhino_document_summary, rhino_get_selected_objects (bridge)
Display 0 5 rhino_zoom_extent, rhino_named_view_save
Scripting 0 2 rhino_execute_python, rhino_execute_csharp
RS Docs 4 4 rhino_search_rhinoscript_functions, rhino_get_rhinoscript_docs
History 0 2 rhino_undo, rhino_redo
Batch 0 1 rhino_batch_modify
Deformation 0 4 rhino_bend, rhino_twist, rhino_taper, rhino_flow_along_curve
NURBS 0 5 rhino_rebuild_surface, rhino_unroll, rhino_surface_from_points
SubD 0 2 rhino_create_subd, rhino_subd_to_nurbs
Srf Match 0 3 rhino_match_surface, rhino_blend_surface_edges, rhino_merge_surfaces
Extraction 0 4 rhino_dup_edge, rhino_dup_border, rhino_isocurve, rhino_make2d
Ctrl Points 0 2 rhino_get_control_points, rhino_set_control_points
Paneling 0 3 rhino_panelize_surface, rhino_create_uv_grid, rhino_panel_frames
Grasshopper 0 22 gh_set_slider, gh_bake_to_rhino, gh_data_tree_get
Drawing 2 5 rhino_drawing_sheet_create, rhino_drawing_title_block_add, rhino_drawing_view_place (bridge)
Schedule 5 5 rhino_schedule_by_layer, rhino_schedule_by_user_text, rhino_object_quantity
Blocks 3 5 rhino_block_define, rhino_block_insert, rhino_block_explode (bridge)
Environment 3 4 rhino_sun_position, rhino_sun_path, rhino_shadow_project
Freeform 8 11 rhino_skin_from_sections, rhino_panel_curvature_classify, rhino_attractor_displace_points
BIM I/O 1 4 rhino_bim_metadata_set, rhino_export_ifc (bridge), rhino_import_ifc (bridge), rhino_export_gbxml (bridge)
Materials+ 2 3 rhino_material_preset_list, rhino_material_preset_create, rhino_environment_set (bridge)
Render 0 5 rhino_camera_set, rhino_light_add, rhino_render_setup, rhino_render_to_file, rhino_turntable_render
Daylight 2 2 rhino_direct_irradiance, rhino_daylight_factor

Detailed signatures live in docs/en/tools-reference.md.

Grasshopper integration

1. Start Rhino 8 → open Grasshopper → load your `.gh` definition.
2. Ensure the C# bridge plugin (`rhino-mcp.rhp`) is loaded in Rhino.
3. Set `RHINO_MCP_FORCE_MODE=bridge` and restart rhino-mcp.
4. From Claude:
   - "Open /work/wing.gh, set the 'span' slider to 12.5, run, bake to layer 'Wing'."
   - "Read the output of the 'Voronoi' component as a DataTree."

See docs/en/grasshopper-guide.md for canvas/component/cluster recipes.

Configuration

Every knob is controlled by an environment variable. CLI flags override env where applicable.

Variable Default Purpose
RHINO_MCP_TRANSPORT stdio stdio or http (Streamable HTTP)
RHINO_MCP_FORCE_MODE (auto) Force standalone or bridge
RHINO_MCP_BRIDGE_OPTIONAL 0 When 1 and RHINO_MCP_FORCE_MODE=bridge, fall back to standalone if the bridge is unreachable (recommended for HTTP connectors).
RHINO_MCP_TRANSPORT_KIND (auto) Bridge transport selector: pipe / unix / tcp
RHINO_HOST, RHINO_PORT localhost:4242 TCP transport endpoint
RHINO_MCP_PIPE rhino_mcp Windows named-pipe name
RHINO_MCP_SOCKET (XDG runtime) Unix socket path override
RHINO_MCP_BRIDGE_TIMEOUT 1 (auto), 5 (forced) Seconds to wait for a bridge ping
RHINO_MCP_RECONNECT_RETRIES 1 Max reconnect attempts after a transient transport failure
RHINO_MCP_RECONNECT_BASE_DELAY 0.5 Base delay (seconds) for exponential backoff
RHINO_MCP_RECONNECT_JITTER 0.25 Symmetric jitter ratio (0 disables, useful for tests)
RHINO_MCP_LOG_LEVEL INFO Stderr log level. Set DEBUG to see every bridge JSON-RPC call.

Development

git clone https://github.com/easehee/rhino-mcp.git
cd rhino-mcp
uv venv && source .venv/bin/activate
uv pip install -e '.[dev]'

# Tests + coverage
uv run pytest --cov=src/rhino_mcp

# Lint + type check
uv run ruff check src/ tests/
uv run mypy src/rhino_mcp

# Build the C# bridge plugin (auto-installs into Rhino on macOS/Windows)
./scripts/build-plugin.sh --release

# Wheel + sdist
./scripts/build.sh

Manual smoke test against a running server

# Terminal A — start the server with verbose logging
RHINO_MCP_LOG_LEVEL=DEBUG rhino-mcp --transport http --port 8765

# Terminal B — list tools via the MCP inspector or a curl probe
npx @modelcontextprotocol/inspector http://127.0.0.1:8765/mcp

Troubleshooting

Symptom Likely cause / remediation
Cannot reach Rhino bridge. Start Rhino 8 with the C# bridge plugin loaded; verify RHINO_HOST/RHINO_PORT.
Bridge-only tool absent in Claude Server is in standalone mode — load the bridge plugin or set RHINO_MCP_FORCE_MODE=bridge.
Invalid parameter: axis (cylinder) Standalone supports only {x:0,y:0,z:1}; switch to bridge for arbitrary axes.
non-3DM import error Standalone import is .3dm-only; use bridge mode for STEP/IGES/DXF.
transport failure on tcp://... The bridge crashed or Rhino was closed — rhino-mcp will reconnect with exponential backoff (RHINO_MCP_RECONNECT_RETRIES).
Stdout corrupted under stdio transport Always log to stderr; rhino-mcp does this — verify no third-party libraries print to stdout.
image_base64 missing from screenshot Caller passed as_base64=False (default) or the screenshot file failed to write — check the summary.path and base64_error fields.
Pagination loops forever Always advance offset by pagination.returned, not by limit; the last page may be partial.
rhino_object_select returns 0 matches Filters AND together — try removing one filter at a time; the color filter only works on objects with ColorSource=ColorFromObject.

More in docs/en/troubleshooting.md.

License

MIT — see LICENSE.

About

MCP Server for Rhino and Grasshopper

Topics

Resources

Contributing

Stars

8 stars

Watchers

2 watching

Forks

Releases

Contributors

Languages