Skip to main content

Lambda MCP: teach your LLM to do Grasshopper tricks.

Project description

LAMCP

PyPI version Python versions License: MIT Build

LAmbda MCP: teach your LLM to do Grasshopper tricks.

Lets Claude Code (or any MCP client) introspect and mutate a live Grasshopper session in real time: inspect the canvas, wire components, read/write slider values, run RhinoCommon calls, hot-reload modules -all from inside an AI agent loop, without rebuilding userobjects or restarting Rhino.

Quick start

  1. Register with Claude Code:

    claude mcp add lamcp --scope user -- uvx lamcp
    
  2. Install it in Grasshopper: download Lamcp_Bridge.ghuser and drop it into your Grasshopper Components folder (Grasshopper → File → Special Folders → Components Folder).

  3. Activate it: restart Grasshopper, drop the LAMCP Bridge component (under the LAMCP tab) on the canvas, wire a Boolean Toggle set to True into enable.

Done!

See Setup for alternative install paths (without uvx, project-scoped, paste-from-source) and the Tools exposed section for what's available.

Architecture

LLM ──MCP stdio──▶ lamcp (Python 3.10+)
                          │
                          │  HTTP POST /exec  {"code": "...", "timeout": 30}
                          ▼
                  LAMCP Bridge GH component (Rhino 8 CPython 3.9)
                     ├─ http.server on 127.0.0.1:8765
                     ├─ exec() with shared globals
                     └─ returns {stdout, stderr, result, error}

Why split: Rhino 8's CPython runtime is pinned to 3.9. fastmcp and the underlying mcp SDK require 3.10+. So the MCP-speaking half runs in a system Python and forwards over loopback HTTP to a stdlib-only HTTP server living inside Rhino as a regular Grasshopper component.

Setup

1. Register with Claude Code

LAMCP is a dev tool you'll want available everywhere, so register it at user scope. The friction-free path uses uvx so no explicit install of lamcp is needed — it'll be fetched and cached on first invocation:

claude mcp add lamcp --scope user -- uvx lamcp

Or, if you'd rather install lamcp into your environment first:

pip install lamcp     # or: uv tool install lamcp
claude mcp add lamcp --scope user -- lamcp

Pick the right --scope. Without --scope, claude mcp add defaults to local scope, which only loads the server when Claude Code is launched from the exact directory you ran the command in. That's almost never what you want for a dev tool. Your options:

Scope Stored in Use when
user ~/.claude.json (top-level mcpServers) You want LAMCP available in every project
project <repo>/.mcp.json (committed to git, shared with collaborators) Your whole team should get LAMCP for one project
local ~/.claude.json under the current project entry (default) You're temporarily trying it in one directory

Verify the registration:

claude mcp list

The new tools are available in any new Claude Code conversation.

Using a different MCP client? Point it at the lamcp command (or uvx lamcp) over stdio.

2. Install the bridge in Grasshopper

Option A — drop the pre-built userobject (recommended).

  1. Download Lamcp_Bridge.ghuser from the latest release.
  2. In Grasshopper: File → Special Folders → Components Folder. Move the .ghuser file there.
  3. Restart Grasshopper. LAMCP Bridge appears under the LAMCP tab.
  4. Drop it on the canvas, wire a Boolean Toggle (set to True) into enable. The status output reads listening on http://127.0.0.1:8765.

Option B — paste the source manually (for hacking).

  1. Drop a Python 3 Script component on the canvas. Paste the contents of grasshopper/Lamcp_Bridge/code.py in.
  2. Add two inputs: enable (bool) and port (int). Add one output: status.
  3. Wire a Boolean Toggle (set to True) into enable.
  4. The status output should read listening on http://127.0.0.1:8765.

Either way, your MCP client now has a run_python_script tool that exec()s code inside your live Rhino session.

Tools exposed

Tool Purpose
run_python_script exec() arbitrary Python inside Rhino, capture stdout / stderr / repr(_)
unload_python_modules drop sys.modules[prefix.*] so the next import re-reads from disk
bridge_health ping the bridge to verify it's reachable

Return contract for run_python_script

{
  "stdout": "...",            // captured stdout
  "stderr": "...",            // captured stderr
  "result": "repr of _",      // assign to `_` to return a value
  "error": null               // formatted traceback if exception raised
}

Globals persist between calls, so you can import once and reuse:

# call 1
import scriptcontext as sc; doc = sc.doc.ActiveDoc
# call 2
print(doc.Name)   # `doc` is still bound

Environment variables

Variable Default Purpose
LAMCP_BRIDGE_URL http://127.0.0.1:8765 URL of the bridge's HTTP server

Caveats

  • UI thread: code runs on the HTTP server thread, not the Rhino UI thread. Most read-only RhinoCommon / Grasshopper access works cross-thread, but heavy mutations (bulk RemoveObject, etc.) can crash Rhino. Eto-based UI marshalling is a planned addition.
  • isinstance doesn't always work: in Rhino 8 CPython, isinstance against concrete .NET types often returns False due to interface interop. Use obj.GetType().Name == "..." instead.
  • RemoveSource(IGH_Param) is a silent no-op: use the RemoveSource(Guid) overload.
  • float(System.Decimal) raises: wrap with System.Convert.ToDouble(x) or float(str(x)).

Security

The bridge listens on 127.0.0.1 only and accepts no auth: it runs arbitrary Python in your Rhino with no sandboxing. Never expose it beyond localhost, and stop it (enable=False) when you're done.

Development

Install with the dev extra to pull in ruff:

pip install -e ".[dev]"

Lint + format checks (same commands CI runs):

ruff check .                # lint
ruff format --check .       # formatting (non-destructive)

Auto-fix:

ruff check . --fix          # fix lint issues
ruff format .               # reformat

For one-off runs without installing into your env, uvx ruff ... works identically.

Releases are tag-driven — see RELEASING.md.

License

MIT

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

lamcp-0.1.1.tar.gz (107.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

lamcp-0.1.1-py3-none-any.whl (8.2 kB view details)

Uploaded Python 3

File details

Details for the file lamcp-0.1.1.tar.gz.

File metadata

  • Download URL: lamcp-0.1.1.tar.gz
  • Upload date:
  • Size: 107.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for lamcp-0.1.1.tar.gz
Algorithm Hash digest
SHA256 3af8570d964973e1a90fac3e8907ff15b26fd5a4b537f3eed325af0ae803337e
MD5 3a748491530a7dc8fa889973e2d926bf
BLAKE2b-256 526d02ec85280cea428e078a2919b013fd490c7d41a6ec95ca1d579b53453b56

See more details on using hashes here.

Provenance

The following attestation bundles were made for lamcp-0.1.1.tar.gz:

Publisher: release.yml on gramaziokohler/lamcp

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file lamcp-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: lamcp-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 8.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for lamcp-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 bf515e587f0bf054a0df5c6b0a31f7dea092c9c87822466961a2bee8ea360bd6
MD5 e54c646448ca87ef689ada55e970c9e5
BLAKE2b-256 9ca19f12b476321e1a36c674e86e30f5cba1d14224d60e3c5af5884ece0de611

See more details on using hashes here.

Provenance

The following attestation bundles were made for lamcp-0.1.1-py3-none-any.whl:

Publisher: release.yml on gramaziokohler/lamcp

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page