* fix: lots of fixes and name refactoring * feat: Add workbench preferences * fix: MCP bridge status widget and just command fixes * fix(tests): Use the correct mesa-glx package * fix(ci): Add fontconfig to GUI test dependencies FreeCAD GUI was failing to start with: "Fontconfig error: Cannot load default config file: No such file" Added fontconfig and fonts-dejavu-core packages to the GUI test job dependencies to resolve the font configuration issue. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * refactor(addon): Extract path utilities into shared module Create path_utils.py module that consolidates duplicated path-finding logic from commands.py and InitGui.py: - get_addon_path(): Find addon directory with caching and fallbacks - get_icon_path(): Get full path to an icon file - get_icons_dir(): Get path to icons directory - get_workbench_icon(): Get path to workbench main icon This removes ~100 lines of duplicated code while preserving the same behavior including _addon_path_cache and all fallback methods. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix(addon): Prevent stale plugin state on startup failure The StartMCPBridgeCommand.Activated method could leave _mcp_plugin in a partially initialized state if FreecadMCPPlugin.start() failed after the plugin was instantiated. Changes: - Create plugin in a local variable first - Only assign to _mcp_plugin after start() succeeds - Explicitly clear _mcp_plugin and _running_config in exception handlers to ensure clean state for subsequent retry attempts Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: Lot of broad improvements * fix(ci): Use blocking headless_server.py for GUI tests The GUI test was using startup_bridge.py which is non-blocking (designed for interactive use). For CI, even in GUI mode, we need the blocking headless_server.py that calls run_forever() to keep FreeCAD running. GUI features are still available since we use the 'freecad' executable instead of 'freecadcmd'. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * refactor(addon): Rename headless_server.py to blocking_bridge.py The old name was misleading because: - It works with both GUI (freecad) and headless (freecadcmd) modes - The key characteristic is that it BLOCKS with run_forever() New naming convention clarifies the difference: - blocking_bridge.py: Starts bridge and blocks (for CI, servers) - startup_bridge.py: Starts bridge and returns (for interactive GUI) Updated all references across: - GitHub workflow (macro-test.yaml) - Just commands (freecad.just) - Unit tests (test_addon_structure.py) - Documentation (5 files) - CLAUDE.md Also improved the script to detect GUI mode dynamically using FreeCAD.GuiUp and display the appropriate status message. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix(just): Remove erroneous rm of startup_bridge.py on error The startup script is now a permanent source file in the repository, not a generated temporary file. The rm -f would have deleted source code if FreeCAD wasn't found. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: General improvements * fix: Lots of general fixes and only stable to PyPi * fix: small cleanup * fix: Small fixes and hopefully fixes the GUI tests * fix: Add proper library paths for FreeCAD GUI in CI - Create wrapper scripts instead of symlinks for AppImage binaries - Set LD_LIBRARY_PATH, QT_PLUGIN_PATH for GUI mode - Add diagnostic output to identify startup failures * fix: Use apprun for GUI tests in CI * fix: Improving Xvfb tests * fix: GUI tests worlk * chore: remove invalid --no-splash comments * fix: ARM64 architecture support and other fixes * fix: cleanup * test: just commands test suite * test: improve just command tests * fix: more general improvements * fix: more cleanup * fix: more updates * fix: small tweaks --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
20 KiB
FreeCAD Robust MCP Server Tools Reference
This document provides a comprehensive reference for all MCP tools available in the FreeCAD Robust MCP Server.
Overview
The FreeCAD Robust MCP Server exposes tools organized into the following categories:
| Category | Description | Tool Count |
|---|---|---|
| Execution | Python execution and system info | 5 |
| Documents | Document management | 7 |
| Objects | Object creation and manipulation | 22 |
| PartDesign | Parametric solid modeling | 20 |
| Export | Import/export operations | 7 |
| View | View control and screenshots | 18 |
| Macros | Macro management | 6 |
| Total | 85 |
Execution Tools
Tools for executing Python code and getting system information.
execute_python
Execute arbitrary Python code in FreeCAD's context.
execute_python(
code: str,
timeout_ms: int = 30000
) -> dict
Parameters:
code: Python code to execute. Use_result_ = valueto return data.timeout_ms: Maximum execution time in milliseconds.
Returns: Execution result with stdout, stderr, and any assigned _result_.
Example:
await execute_python('''
import Part
box = Part.makeBox(10, 20, 30)
_result_ = {"volume": box.Volume}
''')
get_freecad_version
Get FreeCAD version and build information.
get_freecad_version() -> dict
Returns: Version string, build date, Python version, GUI availability.
get_connection_status
Get the current bridge connection status.
get_connection_status() -> dict
Returns: Connection state, mode (xmlrpc/socket/embedded), latency.
get_console_output
Get recent FreeCAD console output.
get_console_output(lines: int = 100) -> list[str]
get_mcp_server_environment
Get environment information about the Robust MCP Server process. Useful for identifying the Robust MCP Server instance via the unique instance_id.
get_mcp_server_environment() -> dict
Returns: Dictionary containing:
instance_id: Unique UUID for this server instance (generated at startup)hostname: Server hostnameos_name: Operating system name (e.g., "Linux", "Darwin", "Windows")os_version: OS version/releaseplatform: Full platform stringpython_version: Python versionfreecad: FreeCAD connection information (connected, mode, version, gui_available, is_headless)env_vars: Selected environment variables (FREECAD_MODE, ports, host)
Document Tools
Tools for managing FreeCAD documents.
list_documents
List all open documents.
list_documents() -> list[dict]
get_active_document
Get the currently active document.
get_active_document() -> dict | None
create_document
Create a new document.
create_document(
name: str = "Unnamed",
label: str | None = None
) -> dict
open_document
Open an existing FreeCAD file.
open_document(path: str) -> dict
save_document
Save a document.
save_document(
doc_name: str | None = None,
path: str | None = None
) -> dict
close_document
Close a document.
close_document(
doc_name: str | None = None,
save_changes: bool = False
) -> dict
recompute_document
Recompute all objects in a document.
recompute_document(doc_name: str | None = None) -> dict
Object Tools
Tools for creating and manipulating FreeCAD objects.
Primitive Creation
create_box
Create a parametric box.
create_box(
length: float = 10.0,
width: float = 10.0,
height: float = 10.0,
name: str | None = None,
doc_name: str | None = None
) -> dict
create_cylinder
Create a parametric cylinder.
create_cylinder(
radius: float = 5.0,
height: float = 10.0,
angle: float = 360.0, # For partial cylinders
name: str | None = None,
doc_name: str | None = None
) -> dict
create_sphere
Create a parametric sphere.
create_sphere(
radius: float = 5.0,
name: str | None = None,
doc_name: str | None = None
) -> dict
create_cone
Create a parametric cone.
create_cone(
radius1: float = 5.0, # Bottom radius
radius2: float = 0.0, # Top radius (0 = pointed)
height: float = 10.0,
angle: float = 360.0,
name: str | None = None,
doc_name: str | None = None
) -> dict
create_torus
Create a torus (donut shape).
create_torus(
radius1: float = 10.0, # Major radius
radius2: float = 2.0, # Minor radius
angle1: float = -180.0,
angle2: float = 180.0,
angle3: float = 360.0,
name: str | None = None,
doc_name: str | None = None
) -> dict
create_wedge
Create a tapered wedge shape.
create_wedge(
xmin: float = 0.0, ymin: float = 0.0, zmin: float = 0.0,
x2min: float = 2.0, z2min: float = 2.0,
xmax: float = 10.0, ymax: float = 10.0, zmax: float = 10.0,
x2max: float = 8.0, z2max: float = 8.0,
name: str | None = None,
doc_name: str | None = None
) -> dict
create_helix
Create a helix curve (for threads, springs).
create_helix(
pitch: float = 5.0,
height: float = 20.0,
radius: float = 5.0,
angle: float = 0.0,
left_handed: bool = False,
name: str | None = None,
doc_name: str | None = None
) -> dict
Object Management
list_objects
List all objects in a document.
list_objects(doc_name: str | None = None) -> list[dict]
inspect_object
Get detailed information about an object.
inspect_object(
object_name: str,
doc_name: str | None = None,
include_properties: bool = True,
include_shape: bool = True
) -> dict
create_object
Create a generic FreeCAD object by type ID.
create_object(
type_id: str, # e.g., "Part::Box", "Sketcher::SketchObject"
name: str | None = None,
properties: dict[str, Any] | None = None,
doc_name: str | None = None
) -> dict
edit_object
Modify object properties.
edit_object(
object_name: str,
properties: dict[str, Any],
doc_name: str | None = None
) -> dict
delete_object
Delete an object.
delete_object(
object_name: str,
doc_name: str | None = None
) -> dict
Boolean Operations
boolean_operation
Perform boolean operations (union, subtract, intersect).
boolean_operation(
operation: str, # "fuse", "cut", or "common"
object1_name: str,
object2_name: str,
result_name: str | None = None,
doc_name: str | None = None
) -> dict
Operations:
fuse- Union/combine shapescut- Subtract object2 from object1common- Intersection of shapes
Transformations
set_placement
Set object position and rotation.
set_placement(
object_name: str,
position: list[float] | None = None, # [x, y, z]
rotation: list[float] | None = None, # [yaw, pitch, roll] in degrees
doc_name: str | None = None
) -> dict
rotate_object
Rotate object around an axis.
rotate_object(
object_name: str,
axis: list[float], # [x, y, z] rotation axis
angle: float, # Degrees
center: list[float] | None = None,
doc_name: str | None = None
) -> dict
scale_object
Scale an object (creates new copy).
scale_object(
object_name: str,
scale: float | list[float], # Uniform or [sx, sy, sz]
result_name: str | None = None,
doc_name: str | None = None
) -> dict
copy_object
Create a copy of an object.
copy_object(
object_name: str,
new_name: str | None = None,
offset: list[float] | None = None, # [x, y, z]
doc_name: str | None = None
) -> dict
mirror_object
Mirror object across a plane.
mirror_object(
object_name: str,
plane: str = "XY", # "XY", "XZ", or "YZ"
result_name: str | None = None,
doc_name: str | None = None
) -> dict
Selection (GUI Mode)
get_selection
Get currently selected objects.
get_selection(doc_name: str | None = None) -> list[dict]
set_selection
Select objects programmatically.
set_selection(
object_names: list[str],
clear_existing: bool = True,
doc_name: str | None = None
) -> dict
clear_selection
Clear the current selection.
clear_selection() -> dict
PartDesign Tools
Tools for parametric solid modeling using the PartDesign workbench.
Bodies and Sketches
create_partdesign_body
Create a PartDesign Body container.
create_partdesign_body(
name: str | None = None,
doc_name: str | None = None
) -> dict
create_sketch
Create a sketch attached to a plane or body.
create_sketch(
body_name: str | None = None,
plane: str = "XY_Plane", # "XY_Plane", "XZ_Plane", "YZ_Plane", or "FaceN"
name: str | None = None,
doc_name: str | None = None
) -> dict
Sketch Geometry
add_sketch_rectangle
Add a rectangle to a sketch.
add_sketch_rectangle(
sketch_name: str,
x: float, y: float, # Bottom-left corner
width: float, height: float,
doc_name: str | None = None
) -> dict
add_sketch_circle
Add a circle to a sketch.
add_sketch_circle(
sketch_name: str,
center_x: float, center_y: float,
radius: float,
doc_name: str | None = None
) -> dict
add_sketch_line
Add a line to a sketch.
add_sketch_line(
sketch_name: str,
x1: float, y1: float, # Start point
x2: float, y2: float, # End point
construction: bool = False,
doc_name: str | None = None
) -> dict
add_sketch_arc
Add an arc to a sketch.
add_sketch_arc(
sketch_name: str,
center_x: float, center_y: float,
radius: float,
start_angle: float, # Degrees
end_angle: float, # Degrees
doc_name: str | None = None
) -> dict
add_sketch_point
Add a point to a sketch (useful for hole centers).
add_sketch_point(
sketch_name: str,
x: float, y: float,
doc_name: str | None = None
) -> dict
Additive Features
pad_sketch
Extrude a sketch to create material.
pad_sketch(
sketch_name: str,
length: float,
symmetric: bool = False,
reversed: bool = False,
name: str | None = None,
doc_name: str | None = None
) -> dict
revolution_sketch
Revolve a sketch around an axis.
revolution_sketch(
sketch_name: str,
angle: float = 360.0,
axis: str = "Base_X", # "Base_X/Y/Z" or "Sketch_V/H"
symmetric: bool = False,
reversed: bool = False,
name: str | None = None,
doc_name: str | None = None
) -> dict
loft_sketches
Loft through multiple sketches.
loft_sketches(
sketch_names: list[str],
ruled: bool = False,
closed: bool = False,
name: str | None = None,
doc_name: str | None = None
) -> dict
sweep_sketch
Sweep a profile along a path.
sweep_sketch(
profile_sketch: str,
spine_sketch: str,
transition: str = "Transformed", # "Transformed", "Right", "Round"
name: str | None = None,
doc_name: str | None = None
) -> dict
Subtractive Features
pocket_sketch
Cut material by extruding a sketch.
pocket_sketch(
sketch_name: str,
length: float,
type: str = "Length", # "Length", "ThroughAll", "UpToFirst", "UpToFace"
name: str | None = None,
doc_name: str | None = None
) -> dict
groove_sketch
Cut material by revolving a sketch.
groove_sketch(
sketch_name: str,
angle: float = 360.0,
axis: str = "Base_X",
symmetric: bool = False,
reversed: bool = False,
name: str | None = None,
doc_name: str | None = None
) -> dict
create_hole
Create parametric holes with optional threading.
create_hole(
sketch_name: str, # Sketch with center point(s)
diameter: float = 6.0,
depth: float = 10.0,
hole_type: str = "Dimension", # "Dimension", "ThroughAll", "UpToFirst"
threaded: bool = False,
thread_type: str = "ISO", # "ISO", "UNC", "UNF"
thread_size: str = "M6",
name: str | None = None,
doc_name: str | None = None
) -> dict
Edge Operations
fillet_edges
Add rounded edges.
fillet_edges(
object_name: str,
radius: float,
edges: list[str] | None = None, # ["Edge1", "Edge2"] or None for all
name: str | None = None,
doc_name: str | None = None
) -> dict
chamfer_edges
Add beveled edges.
chamfer_edges(
object_name: str,
size: float,
edges: list[str] | None = None,
name: str | None = None,
doc_name: str | None = None
) -> dict
Patterns
linear_pattern
Repeat a feature in a linear direction.
linear_pattern(
feature_name: str,
direction: str = "X", # "X", "Y", "Z"
length: float = 50.0,
occurrences: int = 3,
name: str | None = None,
doc_name: str | None = None
) -> dict
polar_pattern
Repeat a feature around an axis.
polar_pattern(
feature_name: str,
axis: str = "Z", # "X", "Y", "Z"
angle: float = 360.0,
occurrences: int = 6,
name: str | None = None,
doc_name: str | None = None
) -> dict
mirrored_feature
Mirror a feature across a plane.
mirrored_feature(
feature_name: str,
plane: str = "XY", # "XY", "XZ", "YZ"
name: str | None = None,
doc_name: str | None = None
) -> dict
Export Tools
Tools for importing and exporting CAD files.
export_step
Export objects to STEP format.
export_step(
file_path: str,
object_names: list[str] | None = None, # None = all visible
doc_name: str | None = None
) -> dict
export_stl
Export objects to STL format (for 3D printing).
export_stl(
file_path: str,
object_names: list[str] | None = None,
doc_name: str | None = None,
mesh_tolerance: float = 0.1
) -> dict
export_3mf
Export objects to 3MF format (modern 3D printing format).
3MF (3D Manufacturing Format) supports richer data than STL, including colors, materials, and print settings. It is increasingly preferred over STL for 3D printing.
export_3mf(
file_path: str,
object_names: list[str] | None = None,
doc_name: str | None = None,
mesh_tolerance: float = 0.1
) -> dict
export_obj
Export objects to OBJ format.
export_obj(
file_path: str,
object_names: list[str] | None = None,
doc_name: str | None = None
) -> dict
export_iges
Export objects to IGES format.
export_iges(
file_path: str,
object_names: list[str] | None = None,
doc_name: str | None = None
) -> dict
import_step
Import a STEP file.
import_step(
file_path: str,
doc_name: str | None = None
) -> dict
import_stl
Import an STL file.
import_stl(
file_path: str,
doc_name: str | None = None
) -> dict
View Tools
Tools for controlling the 3D view and capturing screenshots.
Screenshots
get_screenshot
Capture a screenshot of the 3D view.
Requires GUI mode.
get_screenshot(
view_angle: str = "Isometric",
width: int = 800,
height: int = 600,
doc_name: str | None = None
) -> dict # Returns base64-encoded PNG
View angles: Isometric, Front, Back, Top, Bottom, Left, Right, FitAll
View Control
set_view_angle
Set the 3D view angle.
set_view_angle(
view_angle: str, # Same options as get_screenshot
doc_name: str | None = None
) -> dict
fit_all
Fit all objects in the view.
fit_all(doc_name: str | None = None) -> dict
zoom_in / zoom_out
Zoom the view.
Requires GUI mode.
zoom_in(factor: float = 1.5, doc_name: str | None = None) -> dict
zoom_out(factor: float = 1.5, doc_name: str | None = None) -> dict
set_camera_position
Set custom camera position.
Requires GUI mode.
set_camera_position(
position: list[float], # [x, y, z]
look_at: list[float] | None = None, # Default: origin
doc_name: str | None = None
) -> dict
Object Appearance
set_object_visibility
Show or hide an object.
Requires GUI mode.
set_object_visibility(
object_name: str,
visible: bool,
doc_name: str | None = None
) -> dict
set_display_mode
Set object display mode.
Requires GUI mode.
set_display_mode(
object_name: str,
mode: str, # "Flat Lines", "Shaded", "Wireframe", "Points"
doc_name: str | None = None
) -> dict
set_object_color
Set object color.
Requires GUI mode.
set_object_color(
object_name: str,
color: list[float], # [r, g, b] where values are 0.0-1.0
doc_name: str | None = None
) -> dict
Workbenches
list_workbenches
List available workbenches.
list_workbenches() -> list[dict]
activate_workbench
Activate a workbench.
activate_workbench(workbench_name: str) -> dict
Common workbenches:
PartWorkbench- Part modelingPartDesignWorkbench- Parametric designSketcherWorkbench- 2D sketchingDraftWorkbench- 2D draftingMeshWorkbench- Mesh operations
Undo/Redo
undo / redo
Undo or redo operations.
undo(doc_name: str | None = None) -> dict
redo(doc_name: str | None = None) -> dict
get_undo_redo_status
Get undo/redo availability.
get_undo_redo_status(doc_name: str | None = None) -> dict
Parts Library
list_parts_library
List available library parts.
list_parts_library() -> list[dict]
insert_part_from_library
Insert a part from the library.
insert_part_from_library(
part_path: str,
name: str | None = None,
position: list[float] | None = None,
doc_name: str | None = None
) -> dict
Utility
get_console_log
Get FreeCAD console output.
get_console_log(lines: int = 50) -> dict
recompute
Force recompute of all objects.
recompute(doc_name: str | None = None) -> dict
Macro Tools
Tools for managing FreeCAD macros.
list_macros
List available macros.
list_macros() -> list[dict]
run_macro
Execute a macro by name.
run_macro(
macro_name: str,
args: dict[str, Any] | None = None
) -> dict
create_macro
Create a new macro.
create_macro(
name: str,
code: str,
description: str = ""
) -> dict
read_macro
Read macro contents.
read_macro(macro_name: str) -> dict
delete_macro
Delete a user macro.
delete_macro(macro_name: str) -> dict
create_macro_from_template
Create macro from a predefined template.
create_macro_from_template(
name: str,
template: str = "basic", # "basic", "part", "sketch", "gui", "selection"
description: str = ""
) -> dict
GUI vs Headless Mode
Some tools require FreeCAD to be running in GUI mode. When running in headless mode, these tools will return an error instead of crashing.
GUI-only tools:
get_screenshotset_object_visibilityset_display_modeset_object_colorzoom_in/zoom_outset_camera_positionget_selection/set_selection/clear_selection
To check mode programmatically:
result = await execute_python("_result_ = FreeCAD.GuiUp")
is_gui_mode = result["result"]
Error Handling
All tools return dictionaries with consistent error handling:
Success:
{
"success": True,
"name": "Box",
"volume": 6000.0,
# ... other fields
}
Failure:
{
"success": False,
"error": "Object not found: MissingBox"
}
For tools that raise exceptions, wrap calls in try/except or check the returned error field.