This project provides a robust integration between AI assistants and FreeCAD CAD software using the Model Context Protocol (MCP). It allows external applications to interact with FreeCAD through a standardized interface, offering multiple connection methods and specialized tools.
Note: This repository is under heavy development. Expect daily commits and potential breaking changes.
This project provides a robust integration between AI assistants and FreeCAD CAD software using the Model Context Protocol (MCP). It allows external applications to interact with FreeCAD through a standardized interface, offering multiple connection methods and specialized tools.
For the most reliable setup, follow these steps:
Setup Environment (One-time): Run the setup script. This clones the repository to ~/.mcp-freecad
, creates a Python virtual environment, downloads the latest stable FreeCAD AppImage, extracts it, and configures the server to use it.
curl -sSL https://raw.githubusercontent.com/jango-blockchained/mcp-freecad/main/scripts/bin/setup_freecad_env.sh | bash
Alternatively, clone the repo and run ./scripts/bin/setup_freecad_env.sh
manually.
Run the MCP Server: Use the installer script (which now just ensures the venv is active and runs the server) or the global command if installed.
# Option A: Run via the installer script in the default location ~/.mcp-freecad/scripts/bin/mcp-freecad-installer.sh # Option B: Run the global command (if installed via install-global.sh) mcp-freecad
This starts the MCP server using the recommended launcher
method with the downloaded and extracted AppImage.
You can also run MCP-FreeCAD in a Docker container for easier deployment and isolation.
Start the container:
docker compose up
Build from scratch (if you've made changes):
docker compose build --no-cache docker compose up
The Docker container exposes the following ports:
The Docker setup consists of:
Dockerfile
: Defines the container with Python 3.12, installs dependencies, and sets up the environmentdocker-compose.yml
: Configures the service, ports, volumes, and restart policies.dockerignore
: Excludes unnecessary files from the containerThis approach is especially useful for CI/CD pipelines or when you need to isolate the MCP-FreeCAD environment from your system.
graph TD subgraph "Client" A["AI Assistant / MCP Client"] end subgraph "Server & Connection" B["MCP Server (freecad_mcp_server.py)"] C["FreeCAD Connection (freecad_connection_manager.py)"] C_Auto{"Auto-Select Method"} end subgraph "Connection Methods (Backends)" D["Server Mode (freecad_socket_server.py)"] E["Bridge Mode (freecad_connection_bridge.py)"] F["Wrapper Mode (freecad_connection_wrapper.py)"] L["Launcher Mode (freecad_connection_launcher.py)"] M["Mock Mode"] end subgraph "FreeCAD Execution" FS["Socket Server inside FreeCAD"] FCLI["FreeCAD CLI"] FSub["FreeCAD via Subprocess"] FAppRun["FreeCAD via AppRun"] G["FreeCAD Instance/Modules"] end %% Client to Server A --> |MCP Request| B %% Server uses Connection Layer B --> |Requests Connection| C %% Connection Logic C --> C_Auto C_Auto -- "Pref=Launcher or Auto" --> L C_Auto -- "Pref=Wrapper or Auto Fail" --> F C_Auto -- "Pref=Server or Auto Fail" --> D C_Auto -- "Pref=Bridge or Auto Fail" --> E C_Auto -- "Pref=Mock or Auto Fail" --> M %% Backends to Execution L --> |"Uses AppRun"| FAppRun F --> |"Uses freecad_subprocess.py"| FSub D --> |"Connects via Socket"| FS E --> |"Calls CLI"| FCLI %% Execution to FreeCAD FAppRun --> G FSub --> G FS --> G FCLI --> G %% Style (Optional) classDef client fill:#cde4ff,stroke:#333,stroke-width:1px; classDef server fill:#ccffcc,stroke:#333,stroke-width:1px; classDef backend fill:#fff0cc,stroke:#333,stroke-width:1px; classDef execution fill:#ffcccc,stroke:#333,stroke-width:1px; class A,B,C,C_Auto client; class D,E,F,L,M backend; class FS,FCLI,FSub,FAppRun,G execution;
This flowchart shows the main components and how different connection methods selected by freecad_connection_manager.py
lead to various ways of executing commands within FreeCAD. The launcher
method, often used with extracted AppImages via AppRun
, is the recommended approach for reliability.
For more detailed flowcharts, see FLOWCHART.md.
freecad_mcp_server.py
)mcp/listTools
, mcp/executeTool
).FreeCADConnection
to interact with FreeCAD using the configured method.config.json
.# Start the server (uses config.json by default) python src/mcp_freecad/server/freecad_mcp_server.py # Start with a specific config python src/mcp_freecad/server/freecad_mcp_server.py --config my_config.json
src/mcp_freecad/freecad_connection_manager.py
)freecad_connection_launcher.py
and AppRun
.freecad_connection_wrapper.py
and freecad_subprocess.py
.freecad_socket_server.py
via sockets.freecad_connection_bridge.py
.from freecad_connection_manager import FreeCADConnection # Auto-connect using settings potentially from config.json # (Ensure config.json is present or provide args) fc = FreeCADConnection(auto_connect=True) if fc.is_connected(): print(f"Connected via: {fc.get_connection_type()}") version_info = fc.get_version() print(f"FreeCAD Version: {version_info}") fc.create_document("TestDocFromScript") else: print("Failed to connect to FreeCAD.")
freecad_connection_launcher.py
)AppRun
from an extracted AppImage. It executes freecad_launcher_script.py
within the launched environment.FreeCADConnection
when the launcher
method is selected (configured in config.json
). Not typically run directly by the user.freecad_connection_wrapper.py
) & Subprocess (freecad_subprocess.py
)freecad_connection_wrapper.py
starts freecad_subprocess.py
in a separate Python process. freecad_subprocess.py
imports FreeCAD modules and communicates with the wrapper via stdio pipes.FreeCADConnection
when the wrapper
method is selected (configured in config.json
). Requires a Python environment where the subprocess can successfully import FreeCAD
.freecad_socket_server.py
)FreeCADConnection
.--connect
mode.Requires# Inside FreeCAD Python Console: exec(open("/path/to/mcp-freecad/freecad_socket_server.py").read())
connection_method: server
in config.json
for the MCP Server to connect. (See docs/FREECAD_SERVER_SETUP.md
)freecad_connection_bridge.py
)freecad
executable.FreeCADConnection
when the bridge
method is selected (configured in config.json
). Requires freecad
to be in the system PATH or the path
correctly set in config.freecad_client.py
)FreeCADConnection
interface (for testing/debugging connection methods, not the MCP server).FreeCADConnection
commands (e.g., creating primitives, getting version) from the terminal.config.json
to determine connection settings.# Test connection and get version python freecad_client.py version # Create a box using the configured connection method python freecad_client.py create-box --length 20 --width 10
The MCP-FreeCAD project is organized with the following directory structure:
mcp-freecad/
├── assets/ # 3D model assets (STL, STEP files)
├── backups/ # Backup files
├── config.json # Main configuration file
├── config.template.json # Template for configuration
├── docs/ # Documentation files
│ ├── FLOWCHART.md # Detailed flow diagrams
│ ├── FREECAD_INTEGRATION.md # FreeCAD integration guide
│ ├── FREECAD_SERVER_SETUP.md # Server setup instructions
│ ├── OPTIMIZATION_FEATURES.md # Performance optimization guide
│ └── PYTHON_INTERPRETER_SETUP.md # Python interpreter configuration
├── examples/ # Example scripts showing API usage
├── freecad_connection_bridge.py # Bridge for CLI interaction with FreeCAD
├── freecad_client.py # Command-line client
├── freecad_connection_manager.py # Unified connection interface
├── freecad_mcp.py # Entry point script
├── freecad_mcp_server.py # MCP server implementation
├── freecad_socket_server.py # Socket-based server for FreeCAD
├── scripts/ # Shell scripts for installation and execution
│ ├── README.md # Scripts documentation
│ └── bin/ # Executable scripts
│ ├── install-global.sh # Global installation script
│ ├── mcp-freecad-installer.sh # Installer/Runner script
│ ├── mcp-freecad # Link target for global install
│ └── setup_freecad_env.sh # Environment setup script (AppImage download/extract)
├── src/ # Source code (contains mcp_freecad package)
│ └── mcp_freecad/
│ ├── __init__.py
│ ├── server/
│ │ ├── __init__.py
│ │ └── freecad_mcp_server.py # The main MCP server implementation
│ ├── freecad_connection_manager.py # Unified connection interface
│ └── ... # Other source files
├── tests/ # Test files
│ └── e2e/ # End-to-end tests
├── .gitignore # Git ignore patterns
├── pyproject.toml # Project metadata and dependencies (PEP 621)
├── LICENSE # Project License
├── README.md # This file
├── Dockerfile # Docker build definition
├── docker-compose.yml # Docker Compose configuration
└── ... # Other config files (.dockerignore, .editorconfig, etc.)
For more details on scripts, see scripts/README.md.
This section provides more details on the different installation and setup options.
This involves two main scripts:
scripts/bin/setup_freecad_env.sh
: Prepares the environment.
~/.mcp-freecad
..venv
) and installs requirements.download_appimage.py
to fetch the latest stable FreeCAD Linux AppImage into ~/.mcp-freecad
.extract_appimage.py
which:
~/.mcp-freecad/squashfs-root
.~/.mcp-freecad/config.json
to use connection_method: launcher
and use_apprun: true
with correct absolute paths.curl -sSL /setup_freecad_env.sh | bash
or ./scripts/bin/setup_freecad_env.sh
scripts/bin/mcp-freecad-installer.sh
: Runs the server.
freecad_mcp_server.py
.setup_freecad_env.sh
or manually.~/.mcp-freecad/scripts/bin/mcp-freecad-installer.sh
or mcp-freecad
(global command).install-global.sh
)mcp-freecad
in /usr/local/bin
pointing to mcp-freecad-installer.sh
in the repo.mcp-freecad
from anywhere.setup_freecad_env.sh
if you want to use the recommended launcher method.# Navigate to the repository (e.g., ~/.mcp-freecad) cd ~/.mcp-freecad # Run the setup script first ./scripts/bin/setup_freecad_env.sh # Then run the global installation script sudo ./scripts/bin/install-global.sh # Needs sudo for /usr/local/bin # Now you can run the server from anywhere mcp-freecad
python download_appimage.py
and python extract_appimage.py /path/to/downloaded.AppImage
yourself.python freecad_mcp_server.py
.This is the primary way to interact with FreeCAD using AI assistants like Claude.
# Start the server using the default config.json python src/mcp_freecad/server/freecad_mcp_server.py # Start with a specific configuration file python src/mcp_freecad/server/freecad_mcp_server.py --config /path/to/your/config.json # Enable debug logging python src/mcp_freecad/server/freecad_mcp_server.py --debug
The server will run and listen for connections from MCP clients.
Use any MCP-compatible client. Example using the reference mcp client
:
# Replace 'mcp client' with the actual client command if different mcp client connect stdio --command "python src/mcp_freecad/server/freecad_mcp_server.py"
Or using uv
if you have a client script like the one in the MCP docs:
uv run path/to/your/mcp_client.py python src/mcp_freecad/server/freecad_mcp_server.py
You can also start FreeCAD with the integrated server using:
./scripts/start_freecad_with_server.sh
This will launch FreeCAD and automatically start the server inside it.
config.json
)The config.json
file controls various aspects of the server. Here is an example reflecting the recommended launcher setup after running extract_appimage.py
:
{ "auth": { // Optional authentication settings "api_key": "development", "enabled": false }, "server": { // MCP server settings "host": "0.0.0.0", "port": 8000, "debug": true, "workers": 1, "name": "mcp-freecad", "version": "0.7.11", "mcp": { "transport": "stdio", // Use stdio for Cursor/local clients "protocol_version": "0.1.0" // ... other MCP settings } }, "freecad": { // FreeCAD connection settings // Paths are set automatically by extract_appimage.py for launcher mode "path": "/home/user/mcp-freecad/squashfs-root/usr/bin/freecad", // Example path "python_path": "/home/user/mcp-freecad/squashfs-root/usr/bin/python", // Example path "module_path": "/home/user/mcp-freecad/squashfs-root/usr/lib/", // Example path "host": "localhost", // Not used by launcher "port": 12345, // Not used by launcher "auto_connect": false, // Connection handled internally "reconnect_on_failure": true, "use_mock": false, "connection_method": "launcher", // *** KEY: Use the launcher method *** "script_path": "/home/user/mcp-freecad/freecad_launcher_script.py", // Script run inside FreeCAD "launcher_path": "/home/user/mcp-freecad/freecad_connection_launcher.py", // Script that starts AppRun "use_apprun": true, // *** KEY: Tells launcher to use AppRun *** "apprun_path": "/home/user/mcp-freecad/squashfs-root/AppRun" // Path to AppRun executable }, "logging": { // Logging configuration "level": "INFO", "file": "mcp_freecad.log", "max_size": 10485760, "backup_count": 3 }, "tools": { // Optional: control which tool groups are enabled "enable_smithery": true, "enable_primitives": true, "enable_model_manipulation": true, "enable_export_import": true, "enable_measurement": true, "enable_code_generator": true // ... other tool settings } // ... other sections like cache, recovery, cors, performance ... }
Note: Replace example paths with your actual absolute paths.
See FREECAD_INTEGRATION.md for more details on integration options.
The MCP server currently exposes the following core tools. Additional toolsets are planned.
freecad.create_document
: Create a new document.freecad.list_documents
: List all open documents.freecad.list_objects
: List objects in a specific document (or active one).freecad.create_box
: Create a box primitive.freecad.create_cylinder
: Create a cylinder primitive.freecad.create_sphere
: Create a sphere primitive.freecad.create_cone
: Create a cone primitive.freecad.boolean_union
: Perform a boolean union (fuse) between two objects.freecad.boolean_cut
: Perform a boolean cut (difference) between two objects.freecad.boolean_intersection
: Perform a boolean intersection (common) between two objects.freecad.move_object
: Move an object to a new absolute position.freecad.rotate_object
: Rotate an object by specified angles.freecad.export_stl
: Export specified objects (or all) to an STL file.(Note: The tool names used in MCP requests might differ slightly, e.g., using underscores instead of dots, depending on the client and server implementation details. Refer to the server's mcp/listTools
output for exact names.)
Here are conceptual examples of using the MCP server with an AI assistant:
User: Create a box 50mm long, 30mm wide, and 20mm high.
Assistant: Okay, I can create that box.
[Tool Call: primitives.create_box (arguments: {"length": 50.0, "width": 30.0, "height": 20.0})]
[Tool Result: {"object_name": "Box", "message": "Created box...", "success": true}]
User: Now export it as box.stl
Assistant: Sure, exporting the model to box.stl.
[Tool Call: export_import.export_stl (arguments: {"file_path": "box.stl", "object_names": ["Box"]})]
[Tool Result: {"file_path": "box.stl", "message": "Exported successfully...", "success": true}]
Assistant: I've exported the box model to `box.stl`.
python src/mcp_freecad/server/freecad_mcp_server.py
can run without immediate errors. Check terminal output.stdio
).config.json
is valid JSON.launcher
method):
extract_appimage.py
: Ensure the AppImage was extracted correctly and config.json
was updated.config.json
Paths: Verify all absolute paths in the freecad
section are correct for your system.squashfs-root/AppRun
has execute permissions (chmod +x
).mcp_freecad.log
(created in the project root if logging starts), freecad_server_stdout.log
, and freecad_server_stderr.log
for errors from freecad_connection_launcher.py
, AppRun
, or the FreeCAD process itself.AppRun
fails to find libraries, ensure LD_LIBRARY_PATH
and PYTHONPATH
are correctly set, potentially within .cursor/mcp.json
if using Cursor, or exported manually if testing in the terminal. The extract_appimage.py
script aims to make this less necessary, but it can be a factor.QT_QPA_PLATFORM=offscreen
). Check logs for GUI-related errors.server
method: Ensure freecad_socket_server.py
is running inside an active FreeCAD instance, listening on the correct host/port configured in config.json
.bridge
method: Verify FreeCAD is installed system-wide and the freecad
command works in your terminal. Check the freecad_path
in config.json
.pip install modelcontextprotocol
.This project is licensed under the MIT License - see the LICENSE file for details.
The MCP server is designed for integration with tools like Cursor IDE.
Configure Cursor: Add the MCP server in Cursor's settings (Settings > Features > MCP Servers > Add New MCP Server). Configure it to run the Python script directly, setting the necessary environment variables and working directory. An example configuration in .cursor/mcp.json
would look like this:
{ "mcpServers": { "mcp-freecad": { "command": "python3", // Command to run python "args": [ "src/mcp_freecad/server/freecad_mcp_server.py" // Corrected script path ], "env": { // Environment variables needed for headless AppRun "QT_QPA_PLATFORM": "offscreen", "DISPLAY": "", "FREECAD_CONSOLE": "1", "PYTHONNOUSERSITE": "1", // These might be needed if AppRun doesn't set them automatically "LD_LIBRARY_PATH": "/path/to/mcp-freecad/squashfs-root/usr/lib:/path/to/mcp-freecad/squashfs-root/usr/Ext:...", "PYTHONPATH": "/path/to/mcp-freecad/squashfs-root/usr/lib/python3.11/site-packages:..." }, "cwd": "/path/to/mcp-freecad" // Set working directory to project root } // ... other servers like memory ... } }
Replace /path/to/mcp-freecad
with the actual absolute path to your project.
Ensure the LD_LIBRARY_PATH
and PYTHONPATH
match your AppImage structure if needed.
Restart Cursor: Fully restart Cursor for the configuration changes to take effect.
Server Communication: The server uses stdio
transport by default (configured in config.json
under server.mcp.transport
), which is compatible with Cursor's communication protocol. Errors should be reported back to Cursor via MCP error responses.
freecad_mcp_server.py
script loads config.json
by default. Ensure this file contains the correct settings, especially the freecad
section updated by extract_appimage.py
..cursor/mcp.json
are crucial for allowing the launcher
method to work correctly within the environment Cursor provides.AppRun
from an extracted AppImage. Most reliable.extract_appimage.py
.config.json
):{ "freecad": { "connection_method": "launcher", "use_apprun": true, "apprun_path": "/path/to/squashfs-root/AppRun", ... } }
config.json
):{ "freecad": { "connection_method": "wrapper", ... } }
freecad_socket_server.py
inside FreeCAD.config.json
):{ "freecad": { "connection_method": "server", "host": "localhost", "port": 12345, ... } }
freecad
command-line tool. Can be slower/less reliable.config.json
):{ "freecad": { "connection_method": "bridge", "freecad_path": "/path/to/system/freecad", ... } }
config.json
):{ "freecad": { "connection_method": "mock", "use_mock": true } }
connection_method
is missing or set to "auto"
.Basic FreeCAD Operations
Model Manipulation
Measurement Tools
Primitive Creation
Export/Import Operations
Code Generation
Cursor IDE Integration
AI Assistant Integration
Command Line Usage
# Create a new document freecad.create_document("Prototype") # Add basic shapes primitives.create_box(length=100, width=50, height=20) # Export for 3D printing export_import.export_stl("prototype.stl")
# Import and modify multiple files for file in files: import_step(file) model_manipulation.scale(1.5) export_stl(f"{file}_scaled.stl")
{ "server": { "name": "custom-server-name", "version": "1.0.0", "description": "Custom description" } }
{ "tools": { "enable_smithery": true, "enable_primitives": true, "enable_model_manipulation": true, "enable_export_import": true, "enable_measurement": true, "enable_code_generator": true } }
{ "cursor": { "debug": true, "log_level": "DEBUG", "stdio_transport": true } }
scripts/bin/setup_freecad_env.sh
) for the reliable launcher
connection method.bridge
or server
methods, potentially less reliable).Dependencies are managed via pyproject.toml
and installed into the virtual environment during setup.
(This section duplicates the list above - consolidating for clarity)
The currently implemented tools available via MCP are:
freecad.create_document
freecad.list_documents
freecad.list_objects
freecad.create_box
freecad.create_cylinder
freecad.create_sphere
freecad.create_cone
freecad.boolean_union
freecad.boolean_cut
freecad.boolean_intersection
freecad.move_object
freecad.rotate_object
freecad.export_stl
Additional tools covering measurements, other import/export formats, and code generation are planned for future releases.
The project includes end-to-end (E2E) tests to verify system functionality.
These tests verify interactions from the client's perspective using the MCP protocol.
To run all E2E tests:
# Run with mock FreeCAD (default, doesn't require actual FreeCAD installation) ./tests/e2e/run_tests.py # Run with verbose output ./tests/e2e/run_tests.py --verbose # Run with real FreeCAD connection (requires FreeCAD to be installed and configured) ./tests/e2e/run_tests.py --real # Run a specific test file (e.g., test_primitives.py) ./tests/e2e/run_tests.py --single test_primitives.py
The E2E tests are located in the tests/e2e/
directory and are organized by functionality.
To add new E2E tests:
tests/e2e/
directoryMCPClientTestBase
)See existing test files for examples.
The project includes several documentation files for different aspects:
For AI assistants, please refer to the AI_ASSISTANT_GUIDE.md for detailed usage instructions and examples.
Contributions are welcome! Please feel free to submit a Pull Request.
Discover shared experiences
Shared threads will appear here, showcasing real-world applications and insights from the community. Check back soon for updates!