Files
ouranos/ansible/freecad_mcp
Robert Helewka acf3419450 refactor(ansible): rename freecad_mcp env vars and rework deployment
- Drop `FREECAD_MCP_` prefix from env vars (use `FREECAD_*`)
- Update freecad_mcp port from 22032 to 22061
- Document that FreeCAD bridge is required for tool calls
- Replace kottos deployment with pallas deployment
2026-05-30 09:37:56 -04:00
..

FreeCAD Robust MCP Server — Ansible Deployment

Deploys the FreeCAD Robust MCP Server 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:

freecad_mcp:
  hosts:
    caliban.incus:

3. Add host variables

Add to ansible/inventory/host_vars/caliban.incus.yml:

# 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:

services:
  - alloy
  - caliban
  - docker
  - freecad_mcp
  - kernos

4. Run the playbook

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:

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

# 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