The Problem

Teams that need to drive Onshape CAD models from scripts must repeatedly re‑implement REST calls, handle authentication, and manually construct feature geometry. The result is duplicated effort, fragile code, and slow iteration on parametric designs.

What This Does

onshape_mcp implements a lightweight Model Context Protocol (MCP) server that translates concise JSON commands into the full Onshape REST workflow. Core capabilities live in:

  • API layer – onshape_mcp/api/*.py (e.g., client.py, documents.py, partstudio.py, variables.py) wraps authentication, request building, and response parsing.
  • Feature builders – onshape_mcp/builders/*.py (e.g., extrude.py, sketch.py, gear.py, thicken.py) expose Python objects that emit the JSON payload required for each CAD operation.
  • Server – onshape_mcp/server.py hosts a JSON‑RPC endpoint (call_tool, list_tools, main_stdio) that receives commands from a client (Claude Code, CLI, etc.) and routes them through the builders and API.

The repository also ships a test suite (tests/) and extensive markdown docs that describe each tool and the quick‑start flow.

How It Is Wired

Execution begins at onshape_mcp/server.py:2100 in the main function, which creates an SSE (Server‑Sent Events) app and hands control to the call_tool dispatcher (onshape_mcp/server.py:697).

  • call_tool is the hub: 33 callers invoke it, and it reaches 46 distinct functions, making it the highest‑blast‑radius node. Its responsibilities include:
  • Selecting the appropriate builder (e.g., ExtrudeBuilder, SketchBuilder, ThickenBuilder) based on the "tool" field.
  • Converting user‑supplied units via to_meters.
  • Invoking the builder’s build method, which returns a JSON feature description.
  • Sending the feature to Onshape through self.client.post (network call).
  • The API client (onshape_mcp/api/client.py) is instantiated once per server run; its post method ultimately calls requests.post (outside the repo). This is the sole outbound network touch, routed from call_tool → add_feature → self.client.post.
  • Builder modules have low fan‑in (e.g., ExtrudeBuilder is called from 19 places) and modest depth (max 8 levels of nesting). The most connected internal module is onshape_mcp/server (imports 11 other modules, called by 2).
  • No circular imports were detected, so the import graph is stable. However, the large monolithic server.py (≈1,900 lines) and deep nesting in several builders increase cognitive load and risk of regression.

How To Use It

# Clone the fork you will work with
git clone https://github.com/moses-y/onshape-mcp
cd onshape-mcp

# Create a clean virtual environment (Python 3.10+ required)
python -m venv .venv
source .venv/bin/activate   # Windows: .venv\Scripts\activate

# Install the package in editable mode
pip install -e .

# Provide Onshape credentials (required by onshape_mcp/api/client.py)
export ONSHAPE_ACCESS_KEY="YOUR_ACCESS_KEY"
export ONSHAPE_SECRET_KEY="YOUR_SECRET_KEY"

Run the server (the documented CLI entry point):

python -m onshape_mcp.server

The server now listens for JSON‑RPC calls. A typical client payload looks like:

{
  "tool": "extrude",
  "sketchId": "sketch-abc123",
  "depth": 10,
  "units": "mm"
}

The server will route this through call_tool → ExtrudeBuilder.build → client.post, creating an extrude feature in the targeted Part Studio.

Real‑World Use

A CI pipeline for a mechanical‑design library can invoke the MCP server to generate test parts automatically:

import requests, json, os

payload = {
    "tool": "gear",
    "module": 2,
    "teeth": 24,
    "center": [0, 0],
    "planeId": "plane-xyz"
}
resp = requests.post("http://localhost:8000/rpc", json=payload, headers={
    "Authorization": f"Bearer {os.getenv('ONSHAPE_ACCESS_KEY')}"
})
print(resp.json())

The response contains the Onshape feature ID, which downstream scripts can query for geometry validation or export to STEP.

Code Health & Issues

  • High – Pin third‑party GitHub Actions – .github/workflows/test.yml uses codecov/codecov-action@v3. Replace the tag with a commit SHA.
  • High – Add a LICENSE – No license file; legal reuse is undefined.
  • High – Remove continue-on-error – The correctness step in the workflow masks failing tests. Delete the flag.
  • Medium – Declare least‑privilege GITHUB_TOKEN permissions – Workflow lacks a permissions: block. Add contents: read.
  • Medium – Enable Dependabot or Renovate – No automated dependency updates; add .github/dependabot.yml.
  • Medium – Gate PRs with a dependency‑vulnerability scan – No scan step; integrate dependency-review-action or osv-scanner.
  • Medium – Set persist-credentials: false on checkout – Prevents accidental token leakage during post‑install scripts.
  • Medium – Set timeout-minutes on jobs – Prevents runaway CI runs.
  • Medium – Broad exception handling – onshape_mcp/api/client.py and documents.py catch generic Exception. Narrow to specific error types.
  • High – Deep nesting – server.py, builders/extrude.py, builders/sketch.py have indentation depth ≥ 8, making logic hard to follow. Refactor with early returns.
  • High – Oversized files – server.py (≈1,886 lines) and tests/test_server.py are too large for a single responsibility; split into logical modules.
  • High – Duplicated code blocks – Repeated 6‑line snippets across several builders; extract shared helpers.

No lockfile is present, so builds are not reproducible across environments.

The Bottom Line

onshape-mcp delivers a functional bridge between Python scripts and Onshape’s REST API, with a clear separation between API wrappers, geometry builders, and the JSON‑RPC server. It is usable today, but the monolithic server, deep nesting, and duplicated builder logic increase maintenance risk. Adding a license, tightening CI security, and refactoring the large modules would make the project production‑ready for teams that need automated, programmatic CAD generation.