Skip to main content
Glama
hram

FreeCAD MCP

by hram

Server Configuration

Describes the environment variables required to run the server.

NameRequiredDescriptionDefault
FREECAD_MCP_TOKENNoToken to set in the MCP environment when authentication is enabled.

Instructions

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

This server publishes no instructions, or was last inspected before Glama recorded them.

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",
                "YoungModulus": "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_documentsB

Get the list of open documents in FreeCAD.

With include_status=true, also return labels, file paths, GUI modified flags,
needs_save and needs_recompute. Default preserves the list of names.

Returns:
    A list of document names, or a structured status snapshot.
get_document_statusA

Read which open documents need saving, without saving or recomputing anything.

Empty doc_name lists all; otherwise inspect one named document. modified is the
GUI dirty flag (same save-state indicator as the UI), saved_once means saved before,
needs_recompute is independent. needs_save is true for new/modified/missing-file
documents; null means the dirty flag could not be read, never assumed clean.
file_path and file_exists identify the associated disk file. App.save()/saveAs()
can leave the GUI modified flag set; this reports the actual GUI flag honestly.
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:
- A Part-derived solid (e.g. Part::Box, PartDesign::Body) acting as the geometry.
- A Fem::AnalysisPython container created via `create_object`.
- A Fem::MaterialCommon assigned to the geometry, added to the analysis.
- A Fem::FemMeshGmsh referencing the geometry, added to the analysis (the
  mesh is generated automatically when created via `create_object`).
- At least one Fem::ConstraintFixed and one Fem::ConstraintForce (or
  ConstraintPressure) bound to faces of the geometry, added to the analysis.

A SolverCcxTools is auto-created if the analysis has none.

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").
inspect_partA

Inspect world-space valid geometry, planar faces and cylindrical hole candidates.

Start here before assembly work. Face names are temporary references; define_interface
binds them to geometry fingerprints. Does not move parts or change the camera.
Faces are paginated (1..500 per type); follow next_plane_offset/next_cylinder_offset
when present. feature_counts gives full totals.
inspect_regionA

See 1..6 focused views of selected parts, with world-geometry fingerprints.

Default Isometric/Top/Right. Produces native MCP PNG images, temporarily hides other
objects and restores camera/visibility. Requested document must be active in 3D.
size is square pixels (256..1536). Visual evidence supplements check_assembly.
define_interfaceB

Define a mounting interface: planar mating face and >=2 ordered full inner cylinders.

Hole order determines correspondence, including symmetric patterns. Cylinders must
open onto the plane and be perpendicular to it. owner defaults to part; for a
feature inside a PartDesign Body, supply the Body name. No document changes.
plan_alignmentA

Plan rigid placement matching ordered holes and opposing mounting faces. No mutation.

Positive gap follows the fixed face outward normal. Checks all hole matches, refuses
stale geometry and degenerate patterns. Collision scope during apply is the fixed
part plus explicitly named obstacles; include nearby parts. No correspondence guessing.
Review this plan, then apply_alignment. Handles expire after FreeCAD restart/code update.
apply_alignmentA

Apply a fresh plan in one FreeCAD transaction. Refuse reused/stale plans.

Recompute and measure actual hole errors, axes, mating gap and scoped intersections.
Roll back placement if any check fails. Does not save files. Moves Part::Feature or
PartDesign Body; App::Link and App::Part container application are unsupported.
check_assemblyA

Measure current geometry against a plan, without moving it; reports passed=false on failure.

This checks only declared interface geometry and collision scope, not every assembly component, topology intent, mechanical strength, or persistent assembly constraints.

get_assembly_capabilitiesB

Check native addon protocol and supported assembly operations before working.

start_assembly_operationA

Submit a native CAD job immediately; keep request_id to retry the SAME request safely.

Allowed operations are reported by get_assembly_capabilities. No arbitrary Python.
Returns job_id; poll get_assembly_job. Reusing request_id with different args fails.
Idempotency lasts while the job is retained in addon history; jobs survive MCP restart,
but not FreeCAD exit. Use this for long operations instead of waiting on a tool call.
get_assembly_jobA

Poll without waiting for the GUI. Includes durable outcome and native PNGs when done.

outcome_unknown means the GUI exceeded its dispatch budget and may still finish:
continue polling; do not duplicate the mutation. Results last until history eviction
(32 completed jobs) or FreeCAD exit.
cancel_assembly_jobA

Cancel queued jobs or request safe-point cancellation with rollback for running mutations.

Running OCCT calls cannot be interrupted. accepted=true is a request, not proof
of cancellation: poll for terminal state. Once committing begins cancellation is refused.
preview_alignmentA

See the proposed placement without changing the document: cyan ghost + green/orange axes.

Produces native PNGs and removes all temporary scene-graph overlays afterwards.
The plan must be fresh and unapplied. Does not add document objects or move parts.
create_assemblyB

Create a native FreeCAD Assembly containing specified ROOT parts, preserving world poses.

Changes document organization in one transaction. Refuses parts already inside containers. Creates the native joint group. Does not save files.

create_fixed_jointA

Persist verified mounting pose as a native Fixed Joint, grounding the fixed part.

Requires an applied, still-valid plan and both owners directly inside an existing native Assembly with no prior joints. Runs solver then numeric/collision checks; rolls back if they fail. Native joint survives saving/reopening; connectors preserve relative pose, detached from face topology. This is not a general constraint-network editor.

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.5/5.0

Scored across 31 tools

Disambiguation3/5

Most tools target distinct FreeCAD resources or workflow stages, but several clusters overlap: execute_code/execute_code_async/execute_code_headless, get_async_status/get_assembly_job, and the numerous assembly inspection/planning/checking tools. Detailed descriptions help, but an agent can still misselect among the code-execution and job-polling variants.

Naming Consistency4/5

Names are overwhelmingly snake_case with a predictable verb_noun pattern: get_*, create_*, list_*, inspect_*, plan_*, apply_*, start_*, cancel_*. Minor deviations like get_parts_list, get_async_status, and execute_code_headless keep it from being perfectly consistent.

Tool Count2/5

With 31 tools, the surface is heavy for an MCP server and exceeds the typical well-scoped range. Multiple specialized tools are useful for FreeCAD, but several could be consolidated, especially the three execute_code variants and separate job-status pollers.

Completeness4/5

The surface covers document lifecycle, object CRUD, viewing, parts library, FEM, assembly/alignment, and async job management, with execute_code serving as a broad fallback for missing operations. Minor gaps remain, such as explicit save/export/close document tools, but agents can work around them via code execution.

Maintenance

ActivityActive
ResponsivenessNo issues