# FreeCAD Robust MCP Server — Ansible Deployment Deploys the [FreeCAD Robust MCP Server](https://pypi.org/project/freecad-robust-mcp/) to Caliban as a systemd service with HTTP transport. ## Architecture ``` ┌─────────────────────────────────────────────────┐ │ caliban.incus │ │ │ │ ┌──────────────────────┐ │ │ │ freecad-mcp.service │ │ │ │ (streamable-http) │◄─── :22061 ──────────┤◄── MCP Client │ │ venv + PyPI package │ │ │ └──────────────────────┘ │ │ │ │ │ │ xmlrpc :9875 │ │ ▼ │ │ ┌──────────────────────┐ │ │ │ FreeCAD (future) │ │ │ │ XML-RPC server │ │ │ └──────────────────────┘ │ └─────────────────────────────────────────────────┘ ``` ## FreeCAD bridge required for tool calls The service starts and answers the MCP `initialize` handshake **without** FreeCAD running — the XML-RPC connection to FreeCAD is only attempted on the first CAD tool call (lazy connect). So a green Ansible healthcheck means "transport up", **not** "FreeCAD reachable". Actual CAD tool calls require FreeCAD running with the Robust MCP Bridge workbench started, listening on XML-RPC `localhost:9875`. Standing up that bridge (GUI or headless) on Caliban is a separate step from getting this service to boot. ## Prerequisites - Caliban host in Ansible inventory (already exists in Ouranos) - Python 3.11+ on Caliban (already present) ## Deployment ### 1. Copy playbook files to Ouranos Copy the contents of this directory into your Ouranos repo: ``` ansible/freecad_mcp/ ├── deploy.yml ├── .env.j2 └── freecad-mcp.service.j2 ``` ### 2. Add inventory group Add to `ansible/inventory/hosts`: ```yaml freecad_mcp: hosts: caliban.incus: ``` ### 3. Add host variables Add to `ansible/inventory/host_vars/caliban.incus.yml`: ```yaml # FreeCAD Robust MCP Server freecad_mcp_user: harper freecad_mcp_group: harper freecad_mcp_directory: /srv/freecad-mcp freecad_mcp_port: 22061 freecad_mcp_version: "0.5.0" ``` Update `services` list: ```yaml services: - alloy - caliban - docker - freecad_mcp - kernos ``` ### 4. Run the playbook ```bash ansible-playbook freecad_mcp/deploy.yml ``` ## Upgrading To upgrade to a new PyPI version, update `freecad_mcp_version` in host_vars and re-run the playbook. The pip install task will detect the version change and the handler will restart the service. ## Validation The playbook automatically validates the deployment by: 1. Waiting for the HTTP port to become available 2. Sending an MCP `initialize` JSON-RPC request to `/mcp` 3. Verifying a 200 response You can also manually test: ```bash curl -X POST http://caliban.incus:22061/mcp \ -H "Content-Type: application/json" \ -d '{"jsonrpc":"2.0","method":"initialize","id":1,"params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"curl","version":"1.0.0"}}}' ``` ## Service Management ```bash # On Caliban sudo systemctl status freecad-mcp sudo systemctl restart freecad-mcp sudo journalctl -u freecad-mcp -f ``` ## Security The systemd service runs with hardened settings: | Setting | Value | Rationale | |---------|-------|-----------| | `NoNewPrivileges` | `true` | No privilege escalation | | `ProtectSystem` | `strict` | Filesystem is read-only except allowed paths | | `ProtectHome` | `read-only` | Home directories protected | | `PrivateTmp` | `true` | Isolated /tmp namespace | | `ReadWritePaths` | `/srv/freecad-mcp` | Only app directory is writable |