Skip to content

Contributing

Thank you for your interest in contributing to FreeCAD Robust MCP Server!


Development Setup

Prerequisites

  • Python 3.11 (must match FreeCAD's bundled version)
  • mise for tool management
  • FreeCAD 1.0.2 or newer. FreeCAD 1.1.4 or newer is recommended for security; older releases have known vulnerabilities when opening untrusted files.

Initial Setup

git clone https://github.com/spkane/freecad-addon-robust-mcp-server.git
cd freecad-addon-robust-mcp-server

# Install mise if not already installed
curl https://mise.run | sh

# Install project tools and dependencies
mise trust
mise install
just setup

Safety CLI Account (Required for Security Scanning)

This project uses Safety CLI for dependency vulnerability scanning. Safety requires a free account for the safety scan command used in pre-commit hooks.

# Register for a free account (interactive)
uvx --python 3.11 --from safety==3.8.1 safety auth

# Or login if you already have an account
uvx --python 3.11 --from safety==3.8.1 safety auth login

Note: Safety runs in an isolated uvx environment to avoid dependency conflicts with the MCP runtime. Authentication is stored locally and only needs to be done once per machine. If you skip this step, the safety pre-commit hook will fail with an authentication prompt.

CI/CD: Safety runs in CI using the SAFETY_API_KEY repository secret.

Running Tests

# Run unit tests
just testing::unit

# Run with coverage
just testing::cov

# Run all tests including integration
just testing::all

# Run type checking
uv run mypy src/

Code Quality

# Run all pre-commit checks
just quality::check

# Run linting
just quality::lint

# Format code
just quality::format

# Run security checks
just quality::security

Project Structure

freecad-addon-robust-mcp-server/
├── src/freecad_mcp/           # Main package
│   ├── bridge/                # FreeCAD connection bridges
│   ├── tools/                 # MCP tool implementations
│   ├── resources/             # MCP resource implementations
│   ├── prompts/               # MCP prompt templates
│   └── server.py              # Main server entry point
├── freecad/                   # FreeCAD addon namespace package
│   └── RobustMCPBridge/       # Workbench files
├── tests/                     # Test suite
│   ├── unit/                  # Unit tests
│   └── integration/           # Integration tests
├── docs/                      # Documentation
└── just/                      # Justfile modules

Contribution Guidelines

Code Style

  • Follow PEP 8 with 88-character line length (ruff/black)
  • Use type hints for all function signatures
  • Write Google-style docstrings
  • Run just quality::format before committing

Workbench modules are loaded by FreeCAD under the freecad.RobustMCPBridge namespace. Use package-relative imports for sibling workbench modules; adding the workbench directory to sys.path or importing siblings by bare name can collide with other add-ons. Standalone bridge scripts may run without the workbench, so they only reuse its loaded command and status modules when those modules are available. A standalone bridge started first registers its instance with FreeCAD so the workbench commands can adopt it when they load.

Testing

  • Write tests for all new functionality
  • Maintain test coverage
  • Run just all before submitting PRs (runs quality checks + unit tests)
  • Integration tests require FreeCAD (run via CI)

FreeCAD compatibility and security

Changes must work across the supported FreeCAD versions, not just the version installed on the contributor's machine. The minimum supported version is FreeCAD 1.0.2; the GUI compatibility workflow tests that Qt5/PySide2 release and the latest stable Qt6/PySide6 release. It also runs a non-blocking weekly development canary. See the GUI workflow for the current matrix and installation requirements for user-facing security guidance.

For version-dependent changes, verify the actual FreeCAD API and behavior on the affected releases, including failure handling and security implications. Add regression tests that exercise the real FreeCAD integration when practical; mocked tests alone cannot establish that geometry, GUI behavior, or security controls work in FreeCAD. Document any behavior that must differ by version. Run the applicable tests locally where available and describe versions tested, results, and any gaps in the pull request. CI can provide additional coverage; do not claim a platform or release was verified if its test did not run.

Documentation

  • Update docstrings for API changes
  • Update user docs for feature changes
  • Run just documentation::build to build and verify

Commits

  • Use conventional commit format
  • Keep commits focused and atomic
  • Reference issues when applicable

Adding New MCP Tools

  1. Choose the right module in src/freecad_mcp/tools/
  2. Add the tool function with proper docstring:
@mcp.tool()
async def my_new_tool(
    param1: str,
    param2: int = 10,
    doc_name: str | None = None,
) -> dict[str, Any]:
    """Short description of what the tool does.

    Args:
        param1: Description of param1.
        param2: Description of param2.
        doc_name: Document name. Uses active if None.

    Returns:
        Dictionary with result information.
    """
    bridge = await get_bridge()
    code = f'''
# FreeCAD Python code here
_result_ = {{"success": True}}
'''
    result = await bridge.execute_python(code)
    return result.result or {"success": False}
  1. Add tests in the appropriate test file
  2. Update documentation in docs/guide/tools.md
  3. Update capabilities resource in src/freecad_mcp/resources/freecad.py

Adding New Connection Modes

  1. Create a new bridge class in src/freecad_mcp/bridge/
  2. Inherit from FreecadBridge base class
  3. Implement all abstract methods
  4. Add to bridge factory in src/freecad_mcp/bridge/__init__.py
  5. Add configuration option in src/freecad_mcp/config.py
  6. Update documentation

Release Process

Releases are automated via GitHub Actions:

  1. Update the component's RELEASE_NOTES.md file (see Releasing for details)
  2. Bump versions for workbench/macros (MCP Server auto-bumps from tag)
  3. Commit and push changes
  4. Create release tag with just release::tag-<component> X.Y.Z
  5. CI builds and publishes:
  6. PyPI package and Docker images (MCP Server)
  7. GitHub Release archives (workbench and macros)

Future Work

The following items are on the roadmap and welcome contributions:

Embedded Mode Integration Tests

Currently, embedded mode has only mocked unit tests. Adding live integration tests would require:

  1. CI workflow that runs on Linux (embedded mode is Linux-only)
  2. Uses FreeCAD AppImage's bundled Python interpreter
  3. Sets up PYTHONPATH and LD_LIBRARY_PATH to point to AppImage libs
  4. Runs tests with FREECAD_MODE=embedded

Challenge: The AppImage bundles Python 3.11, so tests must run using that interpreter (not the system Python) to avoid ABI incompatibility.

Reference: See macro-test.yaml for how integration tests currently work with xmlrpc mode.


Getting Help


License

The project uses Apache License 2.0. Previously MIT-licensed contributions retain their original terms. See NOTICE for attribution and LICENSE-ICON for the workbench icons.