Skip to main content
Glama
FreeCAD MCP

FreeCAD MCP

by abanerjee84

Server Configuration

Describes the environment variables required to run the server.

NameRequiredDescriptionDefault
--hostNoPoint at FreeCAD on another machine (address).
FREECAD_DIRNoA FreeCAD install directory to search for freecadcmd.
--freecadcmdNoExplicit headless FreeCAD command; overrides discovery.
FREECAD_MCP_TOKENNoToken the addon's server requires. Equivalent to the --auth-token <t> flag.
--only-text-feedbackNoDrop optional screenshots from every reply, far fewer tokens (CLI flag, no value).

Instructions

Guidance the server publishes about itself, which clients place ahead of the tool catalog so the model reads it before choosing anything.

FreeCAD integration through the Model Context Protocol

Capabilities

Features and capabilities supported by this server

Protocol revision2025-11-25

CapabilityDetails
tools
{
  "listChanged": false
}
prompts
{
  "listChanged": false
}
resources
{
  "subscribe": false,
  "listChanged": false
}
experimental
{}

Tools

Functions exposed to the LLM to take actions

NameDescription
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"
    }
    ```
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
        }
    }
    ```
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
get_parts_listB

Get the list of parts in the parts library addon.

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"
    }
    ```
list_documentsA

Get the list of open documents in FreeCAD.

Returns:
    A list of document names.
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.
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").

Prompts

Interactive templates invoked by user choice

NameDescription
asset_creation_strategy

Resources

Contextual data attached and managed by the client

NameDescription

No resources

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