Skip to main content
Glama
FreeCAD MCP

FreeCAD MCP

by abanerjee84

FreeCAD MCP (revised)

Control FreeCAD from an MCP client — Claude Desktop, pi, or any Model Context Protocol host. Create and edit parametric models, run Python inside FreeCAD, take screenshots of the viewport, inspect documents, run headless scripts, and run FEM analyses with CalculiX.

This is a fork of neka-nat/freecad-mcp at upstream commit ec8abf2 (v0.1.30). It carries three fixes found by running the thing against a real FreeCAD on Windows, plus an installer script and an end-to-end test harness. Everything else is upstream, unchanged. See FORK_NOTES.md for the commit-by-commit detail.

Demos of the upstream design: flange, toy car, modelling from a 2D drawing.

What this fork changes

Upstream

Here

First screenshot of a view that has never rendered

solid black frame, tool reports success

forced redraw, flat-frame detection, one re-shoot

execute_code_headless on a Windows/macOS GUI install

freecadcmd not found unless --freecadcmd passed

discovers the executable inside the install directory

Installing the addon

copy the folder by hand, then click Start RPC Server after every launch

python scripts/install_addon.py --auto-start

Tool argument names

undocumented; the prose names fail pydantic validation

listed in docs/tools.md

Live end-to-end test

none

scripts/smoke_test.mjs, exits non-zero on any failed call

Version

0.1.30

0.1.31 (addon/FreeCADMCP/package.xml, the single source for addon and server)

Related MCP server: freecad-tool-server

Architecture

Two components, two Python environments:

  • The addon runs inside FreeCAD's GUI process and serves XML-RPC on 127.0.0.1:9875. Everything touching the document or the viewport is dispatched to the GUI thread.

  • The MCP server is a stdio process your client launches. It translates tool calls into XML-RPC and returns text plus optional screenshots. It needs Python 3.12+; the addon runs on whatever FreeCAD bundles (1.1 ships 3.11). Do not install this package into FreeCAD's own Python.

MCP client ──stdio──> freecad-mcp server ──XML-RPC :9875──> FreeCAD GUI thread
                                    └──subprocess──> freecadcmd (headless)

Requirements

  • FreeCAD 1.0 or 1.1 (this fork was verified against FreeCAD 1.1 on Windows).

  • uv for the server, or any Python 3.12+.

  • Node 18+ only for the smoke harness.

Install

git clone <this repo> && cd freecad-mcp-rev2

# 1. Addon into FreeCAD's user Mod directory, RPC auto-starting
python scripts/install_addon.py --auto-start

# 2. Server environment
uv sync --locked

# 3. Restart FreeCAD. The RPC server comes up on 127.0.0.1:9875 by itself.

install_addon.py picks the Mod directory that actually holds user.cfg — for a versioned install that is %APPDATA%/FreeCAD/v1-1/Mod on Windows, ~/Library/Application Support/FreeCAD/v1-1/Mod on macOS, ~/.local/share/FreeCAD/v1-1/Mod or ~/.FreeCAD/Mod on Linux — and copies the addon so InitGui.py sits directly inside Mod/FreeCADMCP, which is what FreeCAD's package loader requires. It merges freecad_mcp_settings.json rather than overwriting it, so an auth token and an allowed-IP list survive. --check compares what is installed with this checkout; --dest overrides the directory.

Manual copy and platform-specific paths: docs/installation.md.

Connect a client

Claude Desktop (claude_desktop_config.json):

{
  "mcpServers": {
    "freecad": {
      "command": "uv",
      "args": ["--directory", "/absolute/path/to/freecad-mcp-rev2", "run", "--locked", "freecad-mcp"]
    }
  }
}

pi (~/.pi/agent/mcp.json):

{
  "freecad": {
    "type": "local",
    "command": ["uv", "--directory", "E:/path/to/freecad-mcp-rev2", "run", "--locked", "freecad-mcp"],
    "enabled": true,
    "callTimeout": 300000
  }
}

The long callTimeout matters: execute_code_headless starts a second full FreeCAD process and takes 30-60s, and run_fem_analysis defaults to a 600s budget.

Restart the client after editing its config. Keep FreeCAD open.

Flags

Flag / env

Effect

--only-text-feedback

drop optional screenshots from every reply, far fewer tokens

--host <addr>

point at FreeCAD on another machine (see remote connections)

--auth-token <t> / FREECAD_MCP_TOKEN

token the addon's server requires

--freecadcmd <cmd>

explicit headless FreeCAD command; overrides discovery

FREECAD_DIR

a FreeCAD install directory to search for freecadcmd

Tools

17 tools. Argument names exactly as declared — a wrong name is a pydantic validation error, not something to re-guess. * marks required.

Tool

Arguments

create_document

*name

list_documents

—

reload_document

*doc_name

create_object

*doc_name, *obj_type, *obj_name, obj_properties, analysis_name, include_screenshot, view_name

edit_object

*doc_name, *obj_name, *obj_properties, include_screenshot, view_name

delete_object

*doc_name, *obj_name, include_screenshot, view_name

get_objects

*doc_name, include_screenshot, view_name

get_object

*doc_name, *obj_name, include_screenshot, view_name

get_view

*view_name, width, height, focus_object

execute_code

*code, include_screenshot, view_name, timeout

execute_code_async

*code

get_async_status

job_id

execute_code_headless

*code, timeout

get_rpc_status

—

insert_part_from_library

*relative_path, include_screenshot, view_name

get_parts_list

—

run_fem_analysis

*doc_name, *analysis_name, timeout, include_screenshot, view_name

view_name accepts Isometric, Front, Top, Right, Back, Left, Bottom, Dimetric, Trimetric. Screenshots are on by default for the object tools; pass include_screenshot: false for intermediate steps. Full behaviour, including FEM unit rules and the async job lifecycle: docs/tools.md and docs/execution.md.

Headless execution

execute_code_headless runs your script in a separate freecadcmd process, so an OpenCascade segfault in a heavy sweep or boolean kills only the helper, not FreeCAD and its unsaved documents. Discovery order: PATH → install directory (Program Files\FreeCAD 1.1\bin\, FreeCAD.app/Contents/bin/, /opt, /usr/local, ~) → Flatpak. The Windows installer ships bin\freecadcmd.exe and never adds it to PATH, which is why upstream reported "freecadcmd not found" against a working install. Budget 300s for the call.

Checking it

uv sync --locked
uv run --locked pytest -q --basetemp=.ptemp     # 333 passed, 4 skipped
python scripts/install_addon.py --check         # installed == this checkout
node scripts/smoke_test.mjs                     # live calls against running FreeCAD

--basetemp is needed on Windows machines where pytest's default temp base is permission-locked; without it the run errors with WinError 5 before reaching any code.

scripts/smoke_test.mjs covers what pytest cannot: it launches the server over stdio and drives the addon inside the GUI process — status, document, object, edit, get, viewport screenshot, execute_code, execute_code_headless, cleanup. Screenshots land in out/, any failed call makes it exit non-zero, and it prints all calls succeeded. Modes:

node scripts/smoke_test.mjs list
node scripts/smoke_test.mjs call get_view '{"view_name":"Top","focus_object":"Box"}'
node scripts/smoke_test.mjs code 'import FreeCAD; print(list(FreeCAD.listDocuments()))'
FREECAD_MCP_CMD="uvx freecad-mcp" node scripts/smoke_test.mjs   # test a different server build

Security

The XML-RPC endpoint has no authentication by default and no encryption: anything that can reach port 9875 can run arbitrary Python inside FreeCAD as your user. Keep it on loopback. If you enable remote connections, set a token in the addon's Set Auth Token toolbar button and give the server the same value through FREECAD_MCP_TOKEN, allow only specific IPs, and prefer an SSH tunnel. The server also refuses requests that look like they came from a web browser, so a page cannot drive it. Details: docs/configuration.md.

Troubleshooting

Symptom

Cause

Workbench "MCP Addon" missing after restart

wrong copy depth — InitGui.py must sit directly in Mod/FreeCADMCP/; check Report view

Port 9875 in use at startup

something else holds it; the addon releases the listener so you can retry

EFTYPE / uv_spawn on Windows

launch through cmd: ["cmd", "/c", "freecad-mcp"], absolute path to freecad-mcp.exe

Client connects but no model appears

FreeCAD is closed, or the RPC server was never started — get_rpc_status

execute_code blocks every later call

it runs on the GUI thread (90s default, 1800s max); use execute_code_async for long work

Screenshot comes back one flat colour

empty scene. A view that has never rendered now gets a forced redraw and one re-shoot

Version warning on first tool reply

addon and server differ; reinstall the addon from this checkout (--check compares)

Versioning

addon/FreeCADMCP/package.xml is the single version source for both the addon and the server package. PROTOCOL_VERSION stays at 1 — the RPC contract did not move in this fork. Tag v0.1.31-fork marks the fork tip; the base commit is upstream ec8abf2 (v0.1.30).

Licence and attribution

MIT, as upstream. The design, the RPC protocol, and all of the addon's dispatch, validation, FEM and parts-library machinery are neka-nat's; this fork only adds the fixes and tooling listed above. Upstream is MIT © neka-nat.

Available Tools

17 tools
create_documentB

Create a new document in FreeCAD.

Args:
    name: The name of the document to create.

Returns:
    A message indicating the success or failure of the document creation.

Examples:
    If you want to create a document named "MyDocument", you can use the following data.
    ```json
    {
        "name": "MyDocument"
    }
    ```

Inputs: name (required).

create_objectA

Create a new object in FreeCAD.

``obj_type`` must name a type registered in FreeCAD's C++ type system, such
as "Part::", "PartDesign::" or "Fem::" types. A number of FreeCAD features
are implemented in Python rather than C++ and so are not registered types;
of those, these are supported here through dedicated factories, and each
requires the properties listed beside it:

    Part::Tube        InnerRadius, OuterRadius, Height
    Draft::Circle     Radius
    Draft::Rectangle  Length, Height
    Draft::Polygon    FacesNumber, Radius
    Draft::Wire       Points (list of {x, y, z}), optional Closed

Any other Python-implemented type (Draft::Point, Draft::Ellipse, ...) must
be built with ``execute_code`` instead.

Note that the Draft factories name objects themselves, so for those the
returned object_name will differ from the requested obj_name, which is
applied to the object's Label instead. Always use the returned name in
later get_object/edit_object calls.

Args:
    doc_name: The name of the document to create the object in.
    obj_type: The type of the object to create (e.g. 'Part::Box', 'Part::Cylinder', 'Part::Cut', 'PartDesign::Body', etc.).
    obj_name: The name of the object to create.
    obj_properties: The properties of the object to create.
    include_screenshot: Whether to return a screenshot of the model (default True).
        Set to False to save tokens when visual feedback is not needed,
        e.g. for intermediate steps in a longer sequence of changes.
    view_name: The view orientation of the returned screenshot (default "Isometric").
        Pick the view that best shows the change being made.

Returns:
    A message indicating the success or failure of the object creation and a screenshot of the object.

Examples:
    If you want to create a cylinder with a height of 30 and a radius of 10, you can use the following data.
    ```json
    {
        "doc_name": "MyCylinder",
        "obj_name": "Cylinder",
        "obj_type": "Part::Cylinder",
        "obj_properties": {
            "Height": 30,
            "Radius": 10,
            "Placement": {
                "Base": {
                    "x": 10,
                    "y": 10,
                    "z": 0
                },
                "Rotation": {
                    "Axis": {
                        "x": 0,
                        "y": 0,
                        "z": 1
                    },
                    "Angle": 45
                }
            },
            "ViewObject": {
                "ShapeColor": [0.5, 0.5, 0.5, 1.0]
            }
        }
    }
    ```

    If you want to cut one solid out of another, create both solids first,
    then reference them by name as 'Base' and 'Tool'.
    ```json
    {
        "doc_name": "MyPart",
        "obj_name": "Cut",
        "obj_type": "Part::Cut",
        "obj_properties": {
            "Base": "Box",
            "Tool": "Cylinder"
        }
    }
    ```

    If you want to create a pipe with an outer diameter of 250, a 10 wall
    and a length of 500, you can use the following data.
    ```json
    {
        "doc_name": "MyPipe",
        "obj_name": "Pipe",
        "obj_type": "Part::Tube",
        "obj_properties": {
            "OuterRadius": 125,
            "InnerRadius": 115,
            "Height": 500
        }
    }
    ```

    If you want to create a FEM analysis, you can use the following data.
    ```json
    {
        "doc_name": "MyFEMAnalysis",
        "obj_name": "FemAnalysis",
        "obj_type": "Fem::AnalysisPython",
    }
    ```

    If you want to create a FEM constraint, you can use the following data.
    ```json
    {
        "doc_name": "MyFEMConstraint",
        "obj_name": "FemConstraint",
        "obj_type": "Fem::ConstraintFixed",
        "analysis_name": "MyFEMAnalysis",
        "obj_properties": {
            "References": [
                {
                    "object_name": "MyObject",
                    "face": "Face1"
                }
            ]
        }
    }
    ```

    If you want to create a FEM mechanical material, you can use the following data.
    ```json
    {
        "doc_name": "MyFEMAnalysis",
        "obj_name": "FemMechanicalMaterial",
        "obj_type": "Fem::MaterialCommon",
        "analysis_name": "MyFEMAnalysis",
        "obj_properties": {
            "Material": {
                "Name": "MyMaterial",
                "Density": "7900 kg/m^3",
                "YoungsModulus": "210 GPa",
                "PoissonRatio": "0.3"
            }
        }
    }
    ```

    If you want to create a FEM mesh, you can use the following data.
    The `Shape` property is required (legacy `Part` is also accepted).
    On FreeCAD 1.x the size limits are `CharacteristicLengthMax/Min`;
    the legacy `ElementSizeMax/Min` keys are also accepted.
    ```json
    {
        "doc_name": "MyFEMMesh",
        "obj_name": "FemMesh",
        "obj_type": "Fem::FemMeshGmsh",
        "analysis_name": "MyFEMAnalysis",
        "obj_properties": {
            "Shape": "MyObject",
            "CharacteristicLengthMax": 10,
            "CharacteristicLengthMin": 0.1
        }
    }
    ```

Inputs: doc_name (required), obj_name (required), obj_type (required), view_name, +3 more.

delete_objectA

Delete an object in FreeCAD.

Args:
    doc_name: The name of the document to delete the object from.
    obj_name: The name of the object to delete.
    include_screenshot: Whether to return a screenshot of the model (default True).
        Set to False to save tokens when visual feedback is not needed,
        e.g. for intermediate steps in a longer sequence of changes.
    view_name: The view orientation of the returned screenshot (default "Isometric").
        Pick the view that best shows the change being made.

Returns:
    A message indicating the success or failure of the object deletion and a screenshot of the object.

Inputs: doc_name (required), obj_name (required), view_name, include_screenshot.

edit_objectA

Edit an object in FreeCAD. This tool is used when the create_object tool cannot handle the object creation.

Args:
    doc_name: The name of the document to edit the object in.
    obj_name: The name of the object to edit.
    obj_properties: The properties of the object to edit.
    include_screenshot: Whether to return a screenshot of the model (default True).
        Set to False to save tokens when visual feedback is not needed,
        e.g. for intermediate steps in a longer sequence of changes.
    view_name: The view orientation of the returned screenshot (default "Isometric").
        Pick the view that best shows the change being made.

Returns:
    A message indicating the success or failure of the object editing and a screenshot of the object.

Inputs: doc_name (required), obj_name (required), obj_properties (required), view_name, +1 more.

execute_codeA

Execute arbitrary Python code in FreeCAD.

Args:
    code: The Python code to execute.
    include_screenshot: Whether to return a screenshot of the model (default True).
        Set to False to save tokens when the code does not change the model's
        appearance, e.g. analytical or computational scripts whose result is
        printed output, or intermediate steps in a longer sequence of changes.
    view_name: The view orientation of the returned screenshot (default "Isometric").
        Pick the view that best shows the change being made.
    timeout: Positive finite seconds for each of the queue and GUI execution
        budgets, overriding the 90 s default for this call (capped at 1800).
        Raise it for slow work that must
        run on the GUI thread, such as importing or exporting a large STEP
        assembly. Without it the call reports a timeout while the task keeps
        running, and the result is lost even though the work finishes. Prefer
        execute_code_async for heavy pure-geometry work that touches neither
        the document nor the GUI.

Returns:
    A message indicating the success or failure of the code execution, the output of the code execution, and a screenshot of the object.

Inputs: code (required), timeout, view_name, include_screenshot.

execute_code_asyncA

Execute Python code in FreeCAD without waiting for completion.

Use this ONLY for long-running background computations that do NOT touch the
FreeCAD GUI or mutate the FreeCAD document tree directly.

This tool runs the submitted code in a background thread and returns
immediately. Because it does not run on FreeCAD's main GUI thread, the code
must NOT directly call FreeCADGui APIs, manipulate the active view or
selection, create or edit document objects, change object properties, call
doc.recompute(), or save documents. FreeCAD documents and the Coin3D
scenegraph are not thread-safe: writing to them from this thread races the
GUI thread and can wedge FreeCAD's event loop, after which the RPC server
stops responding entirely and FreeCAD must be restarted.

Every document or view write must instead be handed to the GUI thread through
the injected commit() helper:

    commit(fn, timeout=120) -> fn's return value

Scripts share a live namespace. Saved functions can use commit() in later
async calls; calling it from execute_code or a GUI callback raises immediately.
Coordinate concurrent scripts that intentionally modify the same variables.

commit() queues fn on the GUI thread, waits for it, and raises RuntimeError if
dispatch fails or times out. Example:

    fused = base.fuse(addition).removeSplitter()   # slow, safe in background

    def apply():                                   # runs on the GUI thread
        obj.Shape = fused
        doc.recompute()

    commit(apply)

For code that is not dominated by heavy geometry computation, use execute_code
instead. execute_code runs entirely on the FreeCAD GUI thread and is the safe
default for normal FreeCAD automation.

Use execute_code_async only when the heavy part is long-running OCCT geometry
(e.g. fuse/cut/loft on already-fetched shapes) or other CPU-bound computation
that would exceed execute_code's 90 s GUI-thread budget.

Typical usage pattern:
1. Fetch shapes into module-level variables first (via execute_code).
2. Run the heavy computation via execute_code_async.
3. Apply the result inside commit(), or store it in a module-level Python
   variable (not in the FreeCAD document) for a later execute_code call.

Performance note: boolean operations against shapes with many faces (e.g. a
ribbed lid) are expensive. Fuse the additions together first, then apply a
single boolean against the heavy shape, and avoid doc.recompute() unless the
dependency graph really needs it.

Args:
    code: Background-safe Python code to execute. Use commit(fn) for all
        document and view writes.

Returns:
    A message with the job_id of the started background execution.

Inputs: code (required).

execute_code_headlessA

Run a FreeCAD Python script in a separate headless freecadcmd process.

Use this for OCCT work that can crash or block FreeCAD: helical threads
(makeHelix + makePipeShell), lofts and sweeps, booleans with many or
B-spline tools, long parametric rebuilds. A native OpenCascade crash
here only kills the helper process; the GUI and its open documents
survive, and the tool reports the crash signal and the script's output.

The script runs on the MCP server machine, independently of --host, in a
fresh process without GUI: import FreeCAD/Part
yourself, open documents from disk (FreeCAD.openDocument(path)), save
results with doc.save()/saveAs() or Shape.exportBrep(). Nothing from the
execute_code namespace is available. Print progress to stdout; it is
returned when the process ends. After the script saved a .FCStd that is
open in the GUI, call reload_document(doc_name) to show the result.

Args:
    code: Complete Python script for freecadcmd.
    timeout: Positive finite seconds to wait before killing the process
        (default 600). Partial output is preserved on timeout.

Returns:
    Exit status, crash/timeout diagnosis and the script's printed output.

Inputs: code (required), timeout.

get_async_statusA

Report the state of background jobs started by execute_code_async.

Does not use the FreeCAD GUI thread, so it answers even while a job runs.

Args:
    job_id: The id returned by execute_code_async. Empty lists all running
        jobs and up to 20 recently completed jobs.

Returns:
    For one job: its state (running/done/failed), the error and traceback
    when it failed. History is held in memory until FreeCAD exits.

Inputs: job_id.

get_objectA

Get an object from a document. You can use this tool to get the properties of an object to see what you can check or edit.

Args:
    doc_name: The name of the document to get the object from.
    obj_name: The name of the object to get.
    include_screenshot: Whether to return a screenshot of the document (default True).
        Set to False to save tokens when only the object data is needed.
    view_name: The view orientation of the returned screenshot (default "Isometric").

Returns:
    The object and a screenshot of the object.

Inputs: doc_name (required), obj_name (required), view_name, include_screenshot.

get_objectsB

Get all objects in a document. You can use this tool to get the objects in a document to see what you can check or edit.

Args:
    doc_name: The name of the document to get the objects from.
    include_screenshot: Whether to return a screenshot of the document (default True).
        Set to False to save tokens when only the object data is needed.
    view_name: The view orientation of the returned screenshot (default "Isometric").

Returns:
    A list of objects in the document and a screenshot of the document.

Inputs: doc_name (required), view_name, include_screenshot.

get_parts_listB

Get the list of parts in the parts library addon.

Inputs: no named parameters.

get_rpc_statusA

Get RPC and FreeCAD GUI-dispatch health.

This tool does not use FreeCAD's GUI thread, so it remains available after
a GUI operation times out. A ``stuck`` state identifies the operation that
is still running and indicates that FreeCAD may need to be restarted.
``version_check`` is "ok" or says whether the addon or the server needs
updating.

Inputs: no named parameters.

get_viewB

Get a screenshot of the active view.

Args:
    view_name: The name of the view to get the screenshot of.
    The following views are available:
    - "Isometric"
    - "Front"
    - "Top"
    - "Right"
    - "Back"
    - "Left"
    - "Bottom"
    - "Dimetric"
    - "Trimetric"
    width: The width of the screenshot in pixels. If not specified, uses the viewport width.
    height: The height of the screenshot in pixels. If not specified, uses the viewport height.
    focus_object: The name of the object to focus on. If not specified, fits all objects in the view.

Returns:
    A screenshot of the active view.

Inputs: view_name (required), width, height, focus_object.

insert_part_from_libraryA

Insert a part from the parts library addon.

Args:
    relative_path: The relative path of the part to insert.
    include_screenshot: Whether to return a screenshot of the model (default True).
        Set to False to save tokens when visual feedback is not needed,
        e.g. for intermediate steps in a longer sequence of changes.
    view_name: The view orientation of the returned screenshot (default "Isometric").
        Pick the view that best shows the change being made.

Returns:
    A message indicating the success or failure of the part insertion and a screenshot of the object.

Inputs: relative_path (required), view_name, include_screenshot.

list_documentsA

Get the list of open documents in FreeCAD.

Returns:
    A list of document names.

Inputs: no named parameters.

reload_documentA

Close and re-open a document to pick up external file changes.

Use this AFTER the document's .FCStd file has been modified by
something outside of FreeCAD's GUI process — for example, a
headless `freecadcmd` script that edited and saved the file. The
open GUI document is otherwise unaware of on-disk changes; this
tool closes the stale in-memory copy and reopens the file from
disk so the GUI shows current geometry.

Args:
    doc_name: The name of the open document to reload. Must match
        the name shown by ``list_documents``.

Returns:
    A message confirming the document was reloaded, or describing
    the failure (document not loaded, no associated file, etc).
    FreeCAD names the reopened document after the file stem, which
    can differ from ``doc_name`` ("HandleConcept3D" saved as
    handle-concept-3d.FCStd reopens as handle_concept_3d); the reply
    names the document you should use from then on.

Examples:
    ```json
    {
        "doc_name": "chassis"
    }
    ```

Inputs: doc_name (required).

run_fem_analysisA

Run the CalculiX solver on an existing Fem::FemAnalysis container and return summary results.

Prerequisites in the document, all created with `create_object`:
- A Part-derived solid (e.g. Part::Box, PartDesign::Body) acting as the geometry.
- A Fem::AnalysisPython container.
- A material: type "Fem::MaterialCommon" with analysis_name set (built with
  ObjectsFem.makeMaterialSolid) and its Material given as a dict with units,
  e.g. {"Name": "Steel", "YoungsModulus": "210 GPa", "PoissonRatio": "0.3",
  "Density": "7900 kg/m^3"}. A dict read from the material library can
  come back empty; give the values.
- A mesh: type "Fem::FemMeshGmsh" with analysis_name, Shape (the geometry)
  and CharacteristicLengthMax / CharacteristicLengthMin; it is generated
  when created. A section needs several elements across its thickness,
  or bending stress comes out far too low.
- At least one Fem::ConstraintFixed and one Fem::ConstraintForce (or
  ConstraintPressure) whose References are faces of the geometry.
- Set Force with its unit, e.g. "1000 N": create_object/edit_object reject
  unitless values. In existing documents and execute_code, a plain number
  uses millinewtons, so Force = 1000 applies 1 N. The force acts along the
  normal of the loaded face unless Direction links an edge or face;
  Reversed flips it.

A SolverCcxTools is auto-created if the analysis has none. The reply
lists mechanical loads captured in the same GUI operation as the solve
(in N and MPa, with faces and direction). A failed load read stops the solve.
Direction can be set to {"object_name": "Beam", "edge": "Edge1"}.

The solver runs synchronously on the FreeCAD GUI thread and blocks all
other RPC calls for its duration; do not fan out parallel requests.

Returns max von Mises stress (MPa), max/min displacement (mm), node count,
and the working directory CalculiX wrote to. On failure, returns the
prerequisite-check or solver error along with the working directory for
triage.

Args:
    doc_name: Name of the FreeCAD document.
    analysis_name: Name of the Fem::AnalysisPython object.
    timeout: Seconds to wait for the solver (default 600).
    include_screenshot: Whether to return a screenshot of the model (default True).
        Set to False to save tokens when only the numeric results are needed.
    view_name: The view orientation of the returned screenshot (default "Isometric").

Inputs: doc_name (required), analysis_name (required), timeout, view_name, +1 more.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    A3.9/5.0

    Scored across 17 tools

    Disambiguation4/5

    The three code-execution tools (execute_code, execute_code_async, execute_code_headless) share a purpose, but their descriptions draw very explicit boundaries: GUI thread vs. background thread with commit(), vs. separate headless freecadcmd process. Similarly, create_object vs. edit_object is clarified by edit_object's note that it is the fallback when create_object cannot handle the type. Some cognitive load remains in choosing among the execution variants, but the guidance resolves it in practice.

    Naming Consistency4/5

    Nearly all tools follow a verb_noun convention (create_document, list_documents, create_object, edit_object, delete_object, get_object, get_objects, get_view, reload_document, run_fem_analysis), with a coherent shared prefix for the execute_code family. Minor deviations exist: get_parts_list reverses the noun/verb order compared to list_documents, and status getters use get_*_status. Still highly readable and predictable overall.

    Tool Count4/5

    17 tools is at the upper end but each maps to a real capability (document lifecycle, object CRUD, inspection/screenshots, three execution modes, parts library, FEM solving, diagnostics). Nothing looks like padding, and the split of execution modes is justified by real threading hazards in FreeCAD. A slightly lighter surface might merge get_object/get_objects or get_parts_list/insert_part_from_library, but the count is reasonable for the scope.

    Completeness4/5

    Object-level CRUD is fully covered (create/get/list/edit/delete), documents can be created, listed, and reloaded, and there is rendering, scripting, a parts library, diagnostics, and an FEM solve path. Gaps exist around document lifecycle and I/O: there is no explicit close_document, save_document, or STEP/STL import/export tool, though these are reachable via execute_object/create_object properties and the execute_script tools. Agents can work around the gaps, so coverage is strong but not seamless.

    Maintenance

    ActivityActive
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      Not graded
      quality
      D
      maintenance
      Enables AI agents to programmatically build, analyze, and export 3D CAD geometry using FreeCAD through REST or MCP tools.
      MIT
    • F
      license
      Not graded
      quality
      D
      maintenance
      An MCP server that drives a running FreeCAD session, exposing document management, modeling, inspection, snapshot, and optional workbench operations to MCP clients over stdio or authenticated remote HTTP.
      1
      -
    • F
      license
      Not graded
      quality
      C
      maintenance
      Enables AI clients to create, edit, and export CAD models and drawings in a locally installed FreeCAD via MCP.
      3
      -