Skip to main content
Glama
rokibul-mist

rhino-mcp

by rokibul-mist

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 screenshotsrhino_screenshot(as_base64=True) returns the PNG payload inline for visual verification by the LLM.

  • Rich object selectionrhino_object_select filters by glob name pattern, layer, RGB color, object type, and user-text key/value pairs.

  • Pagination on bulk queriesrhino_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 toolkitrhino_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

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.

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.