mcpfreecad is an MCP server for driving a running FreeCAD session. It exposes document management, modeling, inspection, snapshot, and optional workbench operations to MCP clients over stdio or authenticated remote HTTP.
The server is designed around a small Python bridge that is loaded into FreeCAD's embedded interpreter. The MCP process then talks to that bridge over localhost.
stdioand API-key authenticatedremotehttptransports- document lifecycle tools for opening, saving, closing, and enumerating FreeCAD documents
- explicit model inspection via document tree, topology, sketch status, and sketch details tools
- modeling support for Part primitives, PartDesign bodies/pads/pockets, spreadsheets, Draft arrays, and snapshots
- reusable object library backed by BREP plus JSON metadata
- optional workbench integration for helpers such as
freecad.gears, Fasteners, Curves sketch-on-surface workflows, and A2plus assembly operations when available - remote snapshot retrieval through authenticated URLs or tokenized snapshot download URLs
For LLM-facing operating guidance, see LLM_USAGE.md.
There is an accompanying blog article that describes some of the usage and motivation behind this project.
Install from PyPI:
pip install mcpfreecadTo enable remote HTTP mode:
pip install "mcpfreecad[remote]"For local development:
git clone <repository-url>
cd mcpFreeCAD
pip install -e .
pip install -e ".[remote]"- Start FreeCAD.
- Load the bridge module inside the FreeCAD Python console.
- Start
mcpfreecadinstdiomode orremotehttpmode. - Connect your MCP client and call
bridge_status.
Example bridge loading from a checkout:
exec(open("/path/to/mcpFreeCAD/examples/freecad_bridge_loader.py").read(), globals(), globals())The loader starts the bridge on 127.0.0.1:48111 with token change-me. Adjust the example or call start_bridge_server(...) directly if you need different values.
The default configuration path is ~/.config/mcpfreecad.conf.
Example configuration:
{
"mode": "remotehttp",
"logging": {
"level": "INFO"
},
"bridge": {
"host": "127.0.0.1",
"port": 48111,
"token": "change-me",
"timeout_seconds": 30.0
},
"remote_server": {
"transport": {
"uds": "/var/run/mcpfreecad.sock"
},
"url_prefix": "https://mcp.example.com/freecad/"
},
"stdio": {
"library_root": "/srv/mcpfreecad/stdio-library",
"allow_code_execution": true,
"allow_library_write": true,
"allow_snapshots": true
},
"api_keys": [
{
"id": "cad-agent",
"kdf": {
"algorithm": "argon2id",
"salt": "BASE64",
"time_cost": 3,
"memory_cost": 65536,
"parallelism": 1,
"hash_len": 32,
"hash": "BASE64"
},
"library_root": "/srv/mcpfreecad/cad-agent-library",
"allow_code_execution": true,
"allow_library_write": true,
"allow_snapshots": true
}
]
}Generate or rotate a remote API key:
mcpfreecad --config ~/.config/mcpfreecad.conf --genkey cad-agentStdIO mode:
mcpfreecad --config ~/.config/mcpfreecad.confRemote HTTP mode:
mcpfreecad --config ~/.config/mcpfreecad.conf --transport remotehttpThe remote HTTP wrapper accepts:
Authorization: Bearer <token>X-API-Key: <token>?mcp=<token>- legacy
?api_key=<token>
/status is intentionally public so it can be used for health checks.
The FastMCP instance is created with:
TransportSecuritySettings(enable_dns_rebinding_protection=False)That is intentional for reverse-proxy deployments.
Example Apache layout:
ProxyPass /freecad/status http://127.0.0.1:18080/status
ProxyPassReverse /freecad/status http://127.0.0.1:18080/status
ProxyPass /freecad/mcp/ http://127.0.0.1:18080/mcp/
ProxyPassReverse /freecad/mcp/ http://127.0.0.1:18080/mcp/
ProxyPass /freecad/snapshots/ http://127.0.0.1:18080/snapshots/
ProxyPassReverse /freecad/snapshots/ http://127.0.0.1:18080/snapshots/When remote_server.url_prefix is configured, snapshot download URLs are returned as absolute URLs rooted there. Otherwise they fall back to relative ../snapshots/... paths.
capture_snapshot(...) returns:
snapshot_iddownload_urldownload_url_with_token
download_url requires normal MCP auth again.
download_url_with_token is an easier direct-fetch URL for clients that cannot conveniently resend MCP auth. It contains a random in-memory token and returns image/png.
You can also retrieve a registered snapshot inline through:
get_snapshot_base64(snapshot_id="...")
Snapshots are exposed only if they were created through capture_snapshot(...). Arbitrary server files are not downloadable through the snapshot route.
A sample rc.d script is included at freebsd/rc.d/mcpfreecad.
Install it as:
install -m 0555 freebsd/rc.d/mcpfreecad /usr/local/etc/rc.d/mcpfreecadDefault rc.conf settings:
mcpfreecad_enable="YES"
mcpfreecad_config="/usr/local/etc/mcpfreecad.conf"Optional overrides:
mcpfreecad_daemon_user="mcpfreecad"
mcpfreecad_command="/usr/local/bin/mcpfreecad"
mcpfreecad_transport="remotehttp"
mcpfreecad_flags=""
mcpfreecad_pidfile="/var/run/mcpfreecad.pid"mcpfreecad only surfaces optional workbench tools when the corresponding workbench is available on the host. This currently includes support for areas such as:
freecad.gears- Fasteners
- Curves
- A2plus
mcpfreecad/: package sourceexamples/: bridge loader and smoke examplesfreebsd/: FreeBSD service helpertests/: automated test suiteskill/: Codex skill material
Run the Python test suite with:
pytest -qFor bridge-side smoke testing from a checkout:
python3 examples/freecad_bridge_smoke.py
python3 examples/freecad_bridge_smoke.py --with-fasteners